home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / src / extents.c < prev    next >
Encoding:
Text File  |  1995-08-15  |  189.5 KB  |  6,183 lines

  1. /* Copyright (c) 1994, 1995 Amdahl Corporation.
  2.  
  3. This file is part of XEmacs.
  4.  
  5. XEmacs is free software; you can redistribute it and/or modify it
  6. under the terms of the GNU General Public License as published by the
  7. Free Software Foundation; either version 2, or (at your option) any
  8. later version.
  9.  
  10. XEmacs is distributed in the hope that it will be useful, but WITHOUT
  11. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13. for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with XEmacs; see the file COPYING.  If not, write to the Free
  17. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. /* Synched up with: Not in FSF. */
  20.  
  21. /* This file has been Mule-ized with the exception of the extent-replica
  22.    stuff. */
  23.  
  24. /* Originally written by some people at Lucid.
  25.    Hacked on by jwz.
  26.    Start/end-open stuff added by John Rose (john.rose@eng.sun.com).
  27.    Rewritten from scratch by Ben Wing <wing@netcom.com>, December 1994. */
  28.  
  29. /* #### To do:
  30.    Fix map-extent-children?
  31.  */
  32.  
  33. /* Commentary:
  34.  
  35.    Extents are regions over a buffer, with a start and an end position
  36.    denoting the region of the buffer included in the extent.  In
  37.    addition, either end can be closed or open, meaning that the endpoint
  38.    is or is not logically included in the extent.  Insertion of a character
  39.    at a closed endpoint causes the character to go inside the extent;
  40.    insertion at an open endpoint causes the character to go outside.
  41.  
  42.    Extent endpoints are stored using memory indices (see insdel.c),
  43.    to minimize the amount of adjusting that needs to be done when
  44.    characters are inserted or deleted.
  45.  
  46.    (Formerly, extent endpoints at the gap could be either before or
  47.    after the gap, depending on the open/closedness of the endpoint.
  48.    The intent of this was to make it so that insertions would
  49.    automatically go inside or out of extents as necessary with no
  50.    further work needing to be done.  It didn't work out that way,
  51.    however, and just ended up complexifying and buggifying all the
  52.    rest of the code.)
  53.  
  54.    Extent replica endpoints are stored using buffer positions, although
  55.    byte indices would perhaps be more efficient.  This is because 
  56.    extent replica objects can be copied from one string to another and
  57.    don't contain a pointer to the string they refer to; it also
  58.    avoids having to do endpoint adjustment on them, because characters
  59.    can never be inserted into or deleted from a string (but can be
  60.    changed using `aset' or `fillarray', which might change the byte
  61.    indices).
  62.  
  63.    #### Extent replicas should be rethunk.  I think they're a piece
  64.    of shit and ought to be nuked -- instead, extents should just be able
  65.    to exist over strings just like over buffers.  Jamie, who (I think)
  66.    implemented extent replicas in the first place, is understandably
  67.    reluctant to see them go, but so far he hasn't brought up any
  68.    compelling reasons why they need to say. (ben)
  69.  
  70.    Extents are compared using memory indices.  There are two orderings
  71.    for extents and both orders are kept current at all times.  The normal
  72.    or "display" order is as follows:
  73.  
  74.    Extent A is "less than" extent B, that is, earlier in the display order,
  75.    if:    A-start < B-start,
  76.    or if: A-start = B-start, and A-end > B-end
  77.  
  78.    So if two extents begin at the same position, the larger of them is the
  79.    earlier one in the display order (EXTENT_LESS is true).
  80.  
  81.    For the e-order, the same thing holds: Extent A is "less than" extent B
  82.    in e-order, that is, later in the buffer,
  83.    if:    A-end < B-end,
  84.    or if: A-end = B-end, and A-start > B-start
  85.  
  86.    So if two extents end at the same position, the smaller of them is the
  87.    earlier one in the e-order (EXTENT_E_LESS is true).
  88.  
  89.    The display order and the e-order are complementary orders: any
  90.    theorem about the display order also applies to the e-order if you
  91.    swap all occurrences of "display order" and "e-order", "less than"
  92.    and "greater than", and "extent start" and "extent end".
  93.  
  94.    Extents can be zero-length, and will end up that way if their endpoints
  95.    are explicitly set that way or if their detachable property is nil
  96.    and all the text in the extent is deleted. (The exception is open-open
  97.    zero-length extents, which are barred from existing because there is
  98.    no sensible way to define their properties.  Deletion of the text in
  99.    an open-open extent causes it to be converted into a closed-open
  100.    extent.)  Zero-length extents are primarily used to represent
  101.    annotations, and behave as follows:
  102.  
  103.    1) Insertion at the position of a zero-length extent expands the extent
  104.    if both endpoints are closed; goes after the extent if it is closed-open;
  105.    and goes before the extent if it is open-closed.
  106.  
  107.    2) Deletion of a character on a side of a zero-length extent whose
  108.    corresponding endpoint is closed causes the extent to be detached if
  109.    it is detachable; if the extent is not detachable or the corresponding
  110.    endpoint is open, the extent remains in the buffer, moving as necessary.
  111.  
  112.    Note that closed-open, non-detachable zero-length extents behave exactly
  113.    like markers and that open-closed, non-detachable zero-length extents
  114.    behave like the "point-type" marker in Mule.
  115.  
  116.  
  117.    #### The following information is wrong in places.
  118.  
  119.    More about the different orders:
  120.    --------------------------------
  121.  
  122.    The extents in a buffer are ordered by "display order" because that
  123.    is that order that the redisplay mechanism needs to process them in.
  124.    The e-order is an auxiliary ordering used to facilitate operations
  125.    over extents.  The operations that can be performed on the ordered
  126.    list of extents in a buffer are
  127.  
  128.    1) Locate where an extent would go if inserted into the list.
  129.    2) Insert an extent into the list.
  130.    3) Remove an extent from the list.
  131.    4) Map over all the extents that overlap a range.
  132.  
  133.    (4) requires being able to determine the first and last extents
  134.    that overlap a range.
  135.  
  136.    First, define >, <, <=, etc. as applied to extents to mean
  137.      comparison according to the display order.  Comparison between an
  138.      extent E and an index I means comparison between E and the range
  139.      [I, I].
  140.    Also define e>, e<, e<=, etc. to mean comparison according to the
  141.      e-order.
  142.    For any range R, define R(0) to be the starting index of the range
  143.      and R(1) to be the ending index of the range.
  144.    For any extent E, define E(next) to be the extent directly following
  145.      E, and E(prev) to be the extent directly preceding E.  Assume
  146.      E(next) and E(prev) can be determined from E in constant time.
  147.      (This is because we store the extent list as a doubly linked
  148.      list.)
  149.    Similarly, define E(e-next) and E(e-prev) to be the extents
  150.      directly following and preceding E in the e-order.
  151.  
  152.    Now:
  153.  
  154.    Let R be a range.
  155.    Let F be the first extent overlapping R.
  156.    Let L be the last extent overlapping R.
  157.    
  158.    Theorem 1: R(1) lies between L and L(next), i.e. L <= R(1) < L(next).
  159.  
  160.    This follows easily from the definition of display order.  The
  161.    basic reason that this theorem applies is that the display order
  162.    sorts by increasing starting index.
  163.  
  164.    Therefore, we can determine L just by looking at where we would
  165.    insert R(1) into the list, and if we know F and are moving forward
  166.    over extents, we can easily determine when we've hit L by comparing
  167.    the extent we're at to R(1).
  168.  
  169.    Theorem 2: F(e-prev) e< [1, R(0)] e<= F.
  170.  
  171.    This is the analog of Theorem 1, and applies because the e-order
  172.    sorts by increasing ending index.
  173.  
  174.    Therefore, F can be found in the same amount of time as operation (1),
  175.    i.e. the time that it takes to locate where an extent would go if
  176.    inserted into the e-order list.
  177.  
  178.    If the lists were stored as balanced binary trees, then operation (1)
  179.    would take logarithmic time, which is usually quite fast.  However,
  180.    currently they're stored as simple doubly-linked lists, and instead
  181.    we do some caching to try to speed things up.
  182.  
  183.    Define a "stack of extents" (or "SOE") as the set of extents
  184.    (ordered in the display order) that overlap an index I, together with
  185.    the SOE's "previous" extent, which is an extent that precedes I in
  186.    the e-order. (Hopefully there will not be very many extents between
  187.    I and the previous extent.)
  188.  
  189.    Now:
  190.  
  191.    Let I be an index, let S be the stack of extents on I, let F be
  192.    the first extent in S, and let P be S's previous extent.
  193.  
  194.    Theorem 3: The first extent in S is the first extent that overlaps
  195.    any range [I, J].
  196.  
  197.    Proof: Any extent that overlaps [I, J] but does not include I must
  198.    have a start index > I, and thus be greater than any extent in S.
  199.  
  200.    Therefore, finding the first extent that overlaps a range R is the
  201.    same as finding the first extent that overlaps R(0).
  202.  
  203.    Theorem 4: Let I2 be an index such that I2 > I, and let F2 be the
  204.    first extent that overlaps I2.  Then, either F2 is in S or F2 is
  205.    greater than any extent in S.
  206.  
  207.    Proof: If F2 does not include I then its start index is greater
  208.    than I and thus it is greater than any extent in S, including F.
  209.    Otherwise, F2 includes I and thus is in S, and thus F2 >= F.
  210.  
  211. */
  212.  
  213. #include <config.h>
  214. #include "lisp.h"
  215.  
  216. #include "buffer.h" 
  217. #include "debug.h"
  218. #include "device.h"
  219. #include "extents.h"
  220. #include "faces.h"
  221. #include "frame.h"
  222. #include "glyphs.h"
  223. #include "hash.h"
  224. #include "insdel.h"
  225. #include "opaque.h"
  226. #include "process.h"
  227. #include "redisplay.h"
  228.  
  229. /* ------------------------------- */
  230. /*          general macros         */
  231. /* ------------------------------- */
  232.  
  233. #define MAX_INT ((long) ((1L << VALBITS) - 1))
  234.  
  235. /* ------------------------------- */
  236. /*            gap array            */
  237. /* ------------------------------- */
  238.  
  239. /* Note that this object is not extent-specific and should perhaps be
  240.    moved into another file. */
  241.  
  242. /* Holds a marker that moves as elements in the array are inserted and
  243.    deleted, similar to standard markers. */
  244.  
  245. typedef struct gap_array_marker
  246. {
  247.   int pos;
  248.   struct gap_array_marker *next;
  249. } Gap_Array_Marker;
  250.  
  251. /* Holds a "gap array", which is an array of elements with a gap located
  252.    in it.  Insertions and deletions with a high degree of locality
  253.    are very fast, essentially in constant time.  Array positions as
  254.    used and returned in the gap array functions are independent of
  255.    the gap. */
  256.  
  257. typedef struct gap_array
  258. {
  259.   char *array;
  260.   int gap;
  261.   int gapsize;
  262.   int numels;
  263.   int elsize;
  264.   Gap_Array_Marker *markers;
  265. } Gap_Array;
  266.  
  267. Gap_Array_Marker *gap_array_marker_freelist;
  268.  
  269. /* Convert a "memory position" (i.e. taking the gap into account) into
  270.    the address of the element at (i.e. after) that position.  "Memory
  271.    positions" are only used internally and are of type Memind.
  272.    "Array positions" are used externally and are of type int. */
  273. #define GAP_ARRAY_MEMEL_ADDR(ga, memel) ((ga)->array + (ga)->elsize*(memel))
  274.  
  275. /* Number of elements currently in a gap array */
  276. #define GAP_ARRAY_NUM_ELS(ga) ((ga)->numels)
  277.  
  278. #define GAP_ARRAY_ARRAY_TO_MEMORY_POS(ga, pos) \
  279.   ((pos) <= (ga)->gap ? (pos) : (pos) + (ga)->gapsize)
  280.  
  281. #define GAP_ARRAY_MEMORY_TO_ARRAY_POS(ga, pos) \
  282.   ((pos) <= (ga)->gap ? (pos) : (pos) - (ga)->gapsize)
  283.  
  284. /* Convert an array position into the address of the element at
  285.    (i.e. after) that position. */
  286. #define GAP_ARRAY_EL_ADDR(ga, pos) ((pos) < (ga)->gap ? \
  287.   GAP_ARRAY_MEMEL_ADDR(ga, pos) : \
  288.   GAP_ARRAY_MEMEL_ADDR(ga, (pos) + (ga)->gapsize))
  289.  
  290. /* ------------------------------- */
  291. /*          extent list            */
  292. /* ------------------------------- */
  293.  
  294. typedef struct extent_list_marker
  295. {
  296.   Gap_Array_Marker *m;
  297.   int endp;
  298.   struct extent_list_marker *next;
  299. } Extent_List_Marker;
  300.  
  301. typedef struct extent_list
  302. {
  303.   Gap_Array *start;
  304.   Gap_Array *end;
  305.   Extent_List_Marker *markers;
  306. } Extent_List;
  307.  
  308. Extent_List_Marker *extent_list_marker_freelist;
  309.  
  310. #define EXTENT_LESS_VALS(e,st,nd) ((extent_start (e) < (st)) || \
  311.                    ((extent_start (e) == (st)) && \
  312.                     (extent_end (e) > (nd))))
  313.  
  314. #define EXTENT_EQUAL_VALS(e,st,nd) ((extent_start (e) == (st)) && \
  315.                     (extent_end (e) == (nd)))
  316.  
  317. #define EXTENT_LESS_EQUAL_VALS(e,st,nd) ((extent_start (e) < (st)) || \
  318.                      ((extent_start (e) == (st)) && \
  319.                       (extent_end (e) >= (nd))))
  320.  
  321. /* Is extent E1 less than extent E2 in the display order? */
  322. #define EXTENT_LESS(e1,e2) \
  323.   EXTENT_LESS_VALS (e1, extent_start (e2), extent_end (e2))
  324.  
  325. /* Is extent E1 equal to extent E2? */
  326. #define EXTENT_EQUAL(e1,e2) \
  327.   EXTENT_EQUAL_VALS (e1, extent_start (e2), extent_end (e2))
  328.  
  329. /* Is extent E1 less than or equal to extent E2 in the display order? */
  330. #define EXTENT_LESS_EQUAL(e1,e2) \
  331.   EXTENT_LESS_EQUAL_VALS (e1, extent_start (e2), extent_end (e2))
  332.  
  333. #define EXTENT_E_LESS_VALS(e,st,nd) ((extent_end (e) < (nd)) || \
  334.                      ((extent_end (e) == (nd)) && \
  335.                       (extent_start (e) > (st))))
  336.  
  337. #define EXTENT_E_LESS_EQUAL_VALS(e,st,nd) ((extent_end (e) < (nd)) || \
  338.                        ((extent_end (e) == (nd)) && \
  339.                         (extent_start (e) >= (st))))
  340.  
  341. /* Is extent E1 less than extent E2 in the e-order? */
  342. #define EXTENT_E_LESS(e1,e2) \
  343.     EXTENT_E_LESS_VALS(e1, extent_start (e2), extent_end (e2))
  344.  
  345. /* Is extent E1 less than or equal to extent E2 in the e-order? */
  346. #define EXTENT_E_LESS_EQUAL(e1,e2) \
  347.   EXTENT_E_LESS_EQUAL_VALS (e1, extent_start (e2), extent_end (e2))
  348.  
  349. #define EXTENT_GAP_ARRAY_AT(ga, pos) (* (EXTENT *) GAP_ARRAY_EL_ADDR(ga, pos))
  350.  
  351. /* ------------------------------- */
  352. /*    auxiliary extent structure   */
  353. /* ------------------------------- */
  354.  
  355. struct extent_auxiliary extent_auxiliary_defaults;
  356.  
  357. MAC_DEFINE (EXTENT, mactemp_ancestor_extent);
  358. MAC_DEFINE (EXTENT, mactemp_aux_extent);
  359. MAC_DEFINE (EXTENT, mactemp_plist_extent);
  360. MAC_DEFINE (EXTENT, mactemp_ensure_extent);
  361. MAC_DEFINE (EXTENT, mactemp_set_extent);
  362.  
  363. /* ------------------------------- */
  364. /*     buffer-extent primitives    */
  365. /* ------------------------------- */
  366.  
  367. typedef struct stack_of_extents
  368. {
  369.   Extent_List *extents;
  370.   Memind pos;
  371. } Stack_Of_Extents;
  372.  
  373. Lisp_Object Vthis_is_a_dead_extent_replica;
  374.  
  375. /* ------------------------------- */
  376. /*           map-extents           */
  377. /* ------------------------------- */
  378.  
  379. typedef int Endpoint_Index;
  380.  
  381. #define memind_to_startind(x, start_open) \
  382.   ((Endpoint_Index) (((x) << 1) + !!(start_open)))
  383. #define memind_to_endind(x, end_open) \
  384.   ((Endpoint_Index) (((x) << 1) - !!(end_open)))
  385.  
  386. /* Combination macros */
  387. #define bytind_to_startind(buf, x, start_open) \
  388.   memind_to_startind (bytind_to_memind (buf, x), start_open)
  389. #define bytind_to_endind(buf, x, end_open) \
  390.   memind_to_endind (bytind_to_memind (buf, x), end_open)
  391.  
  392. /* ------------------------------- */
  393. /*    extent-object primitives     */
  394. /* ------------------------------- */
  395.  
  396. /* These macros generalize many standard buffer-position functions to
  397.    either a buffer or a string. */
  398.  
  399. /* Converting between Meminds and Bytinds, for an extent object.
  400.    For strings, this is a no-op.  For buffers, this resolves
  401.    to the standard memind<->bytind converters. */
  402.  
  403. #define extent_object_bytind_to_memind(obj, ind) \
  404.   (BUFFERP (obj) ? bytind_to_memind (XBUFFER (obj), ind) : (Memind) ind)
  405.  
  406. #define extent_object_memind_to_bytind(obj, ind) \
  407.   (BUFFERP (obj) ? memind_to_bytind (XBUFFER (obj), ind) : (Bytind) ind)
  408.  
  409. /* Converting between Bufpos's and Bytinds, for an extent object.
  410.    For strings, this maps to the bytecount<->charcount converters. */
  411.  
  412. #define extent_object_bufpos_to_bytind(obj, pos)             \
  413.   (BUFFERP (obj) ? bufpos_to_bytind (XBUFFER (obj), pos) :        \
  414.    (Bytind) charcount_to_bytecount (string_data (XSTRING (obj)), pos))
  415.  
  416. #define extent_object_bytind_to_bufpos(obj, ind)             \
  417.   (BUFFERP (obj) ? bytind_to_bufpos (XBUFFER (obj), ind) :        \
  418.    (Bufpos) bytecount_to_charcount (string_data (XSTRING (obj)), ind))
  419.  
  420. /* Similar for Bufpos's and Meminds. */
  421.  
  422. #define extent_object_bufpos_to_memind(obj, pos)             \
  423.   (BUFFERP (obj) ? bufpos_to_memind (XBUFFER (obj), pos) :        \
  424.    (Memind) charcount_to_bytecount (string_data (XSTRING (obj)), pos))
  425.  
  426. #define extent_object_memind_to_bufpos(obj, ind)             \
  427.   (BUFFERP (obj) ? memind_to_bufpos (XBUFFER (obj), ind) :        \
  428.    (Bufpos) bytecount_to_charcount (string_data (XSTRING (obj)), ind))
  429.  
  430. /* Similar for Bytinds and start/end indices. */
  431.  
  432. #define extent_object_bytind_to_startind(obj, ind, start_open)        \
  433.   memind_to_startind (extent_object_bytind_to_memind (obj, ind),    \
  434.               start_open)
  435.  
  436. #define extent_object_bytind_to_endind(obj, ind, end_open)        \
  437.   memind_to_endind (extent_object_bytind_to_memind (obj, ind),        \
  438.             end_open)
  439.  
  440. /* absolute and accessible bounds for a string or buffer.
  441.    For a string, this is always just the beginning and end of the string. */
  442.  
  443. #define extent_object_accessible_start(obj)                \
  444.   (BUFFERP (obj) ? BI_BUF_BEGV (XBUFFER (obj)) : (Bytind) 0)
  445.  
  446. #define extent_object_absolute_start(obj)                \
  447.   (BUFFERP (obj) ? BI_BUF_BEG (XBUFFER (obj)) : (Bytind) 0)
  448.  
  449. #define extent_object_accessible_limit(obj)                \
  450.   (BUFFERP (obj) ? BI_BUF_ZV (XBUFFER (obj)) :                \
  451.    (Bytind) string_length (XSTRING (obj)))
  452.  
  453. #define extent_object_absolute_limit(obj)                \
  454.   (BUFFERP (obj) ? BI_BUF_Z (XBUFFER (obj)) :                \
  455.    (Bytind) string_length (XSTRING (obj)))
  456.  
  457. /* ------------------------------- */
  458. /*      Lisp-level functions       */
  459. /* ------------------------------- */
  460.  
  461. /* flags for decode_extent() */
  462. #define DE_MUST_HAVE_BUFFER 1
  463. #define DE_MUST_BE_ATTACHED 2
  464.  
  465. #ifdef ENERGIZE
  466. extern void restore_energize_extent_state (EXTENT extent);
  467. extern struct Energize_Extent_Data *energize_extent_data (EXTENT);
  468. extern Lisp_Object Qenergize;
  469. #endif
  470.  
  471. Lisp_Object Vlast_highlighted_extent;
  472. int mouse_highlight_priority;
  473.  
  474. Lisp_Object Qextentp;
  475. Lisp_Object Qextent_replicap;
  476. Lisp_Object Qextent_live_p;
  477. Lisp_Object Qextent_replica_live_p;
  478.  
  479. Lisp_Object Qend_closed;
  480. Lisp_Object Qstart_open;
  481. Lisp_Object Qall_extents_closed;
  482. Lisp_Object Qall_extents_open;
  483. Lisp_Object Qall_extents_closed_open;
  484. Lisp_Object Qall_extents_open_closed;
  485. Lisp_Object Qstart_in_region;
  486. Lisp_Object Qend_in_region;
  487. Lisp_Object Qstart_and_end_in_region;
  488. Lisp_Object Qstart_or_end_in_region;
  489. Lisp_Object Qnegate_in_region;
  490.  
  491. Lisp_Object Qdup_list; /* used in string_dups() / set_string_dups() */
  492.  
  493. Lisp_Object Qdetached;
  494. Lisp_Object Qdestroyed;
  495. Lisp_Object Qbegin_glyph;
  496. Lisp_Object Qend_glyph;
  497. Lisp_Object Qstart_open;
  498. Lisp_Object Qend_open;
  499. Lisp_Object Qstart_closed;
  500. Lisp_Object Qend_closed;
  501. Lisp_Object Qread_only;
  502. /* Qhighlight defined in general.c */
  503. Lisp_Object Qunique;
  504. Lisp_Object Qduplicable;
  505. Lisp_Object Qinvisible;
  506. Lisp_Object Qintangible;
  507. Lisp_Object Qdetachable;
  508. Lisp_Object Qpriority;
  509.  
  510. Lisp_Object Qglyph_layout;  /* This exists only for backwards compatibility. */
  511. Lisp_Object Qbegin_glyph_layout, Qend_glyph_layout;
  512. Lisp_Object Qoutside_margin;
  513. Lisp_Object Qinside_margin;
  514. Lisp_Object Qwhitespace;
  515. /* Qtext defined in general.c */
  516.  
  517. /* partially used in redisplay */
  518. Lisp_Object Qglyph_invisible;
  519.  
  520. Lisp_Object Qcopy_function;
  521. Lisp_Object Qpaste_function;
  522.  
  523.  
  524. /************************************************************************/
  525. /*                       Generalized gap array                          */
  526. /************************************************************************/
  527.  
  528. /* This generalizes the "array with a gap" model used to store buffer
  529.    characters.  This is based on the stuff in insdel.c and should
  530.    probably be merged with it.  This is not extent-specific and should
  531.    perhaps be moved into a separate file. */
  532.  
  533. /* ------------------------------- */
  534. /*        internal functions       */
  535. /* ------------------------------- */
  536.  
  537. /* Adjust the gap array markers in the range (FROM, TO].  Parallel to
  538.    adjust_markers() in insdel.c. */
  539.  
  540. static void
  541. gap_array_adjust_markers (Gap_Array *ga, Memind from,
  542.               Memind to, int amount)
  543. {
  544.   Gap_Array_Marker *m;
  545.  
  546.   for (m = ga->markers; m; m = m->next)
  547.     m->pos = do_marker_adjustment (m->pos, from, to, amount);
  548. }
  549.  
  550. /* Move the gap to array position POS.  Parallel to move_gap() in
  551.    insdel.c but somewhat simplified. */
  552.  
  553. static void
  554. gap_array_move_gap (Gap_Array *ga, int pos)
  555. {
  556.   int gap = ga->gap;
  557.   int gapsize = ga->gapsize;
  558.  
  559.   assert (ga->array);
  560.   if (pos < gap)
  561.     {
  562.       memmove (GAP_ARRAY_MEMEL_ADDR (ga, pos + gapsize),
  563.            GAP_ARRAY_MEMEL_ADDR (ga, pos),
  564.            (gap - pos)*ga->elsize);
  565.       gap_array_adjust_markers (ga, (Memind) pos, (Memind) gap,
  566.                 gapsize);
  567.     }
  568.   else if (pos > gap)
  569.     {
  570.       memmove (GAP_ARRAY_MEMEL_ADDR (ga, gap),
  571.            GAP_ARRAY_MEMEL_ADDR (ga, gap + gapsize),
  572.            (pos - gap)*ga->elsize);
  573.       gap_array_adjust_markers (ga, (Memind) (gap + gapsize),
  574.                 (Memind) (pos + gapsize), - gapsize);
  575.     }
  576.   ga->gap = pos;
  577. }
  578.  
  579. /* Make the gap INCREMENT characters longer.  Parallel to make_gap() in
  580.    insdel.c. */
  581.  
  582. static void
  583. gap_array_make_gap (Gap_Array *ga, int increment)
  584. {
  585.   char *ptr = ga->array;
  586.   int real_gap_loc;
  587.   int old_gap_size;
  588.  
  589.   /* If we have to get more space, get enough to last a while.  We use
  590.      a geometric progession that saves on realloc space. */
  591.   increment += 100 + ga->numels / 8;
  592.  
  593.   ptr = xrealloc (ptr,
  594.           (ga->numels + ga->gapsize + increment)*ga->elsize);
  595.   if (ptr == 0)
  596.     memory_full ();
  597.   ga->array = ptr;
  598.  
  599.   real_gap_loc = ga->gap;
  600.   old_gap_size = ga->gapsize;
  601.  
  602.   /* Call the newly allocated space a gap at the end of the whole space.  */
  603.   ga->gap = ga->numels + ga->gapsize;
  604.   ga->gapsize = increment;
  605.  
  606.   /* Move the new gap down to be consecutive with the end of the old one.
  607.      This adjusts the markers properly too.  */
  608.   gap_array_move_gap (ga, real_gap_loc + old_gap_size);
  609.  
  610.   /* Now combine the two into one large gap.  */
  611.   ga->gapsize += old_gap_size;
  612.   ga->gap = real_gap_loc;
  613. }
  614.  
  615. /* ------------------------------- */
  616. /*        external functions       */
  617. /* ------------------------------- */
  618.  
  619. /* Insert NUMELS elements (pointed to by ELPTR) into the specified
  620.    gap array at POS. */
  621.  
  622. static void
  623. gap_array_insert_els (Gap_Array *ga, int pos, void *elptr, int numels)
  624. {
  625.   assert (pos >= 0 && pos <= ga->numels);
  626.   if (ga->gapsize < numels)
  627.     gap_array_make_gap (ga, numels - ga->gapsize);
  628.   if (pos != ga->gap)
  629.     gap_array_move_gap (ga, pos);
  630.  
  631.   memcpy (GAP_ARRAY_MEMEL_ADDR (ga, ga->gap), (char *) elptr,
  632.       numels*ga->elsize);
  633.   ga->gapsize -= numels;
  634.   ga->gap += numels;
  635.   ga->numels += numels;
  636.   /* This is the equivalent of insert-before-markers.
  637.  
  638.      #### Should only happen if marker is "moves forward at insert" type.
  639.      */
  640.  
  641.   gap_array_adjust_markers (ga, pos - 1, pos, numels);
  642. }
  643.  
  644. /* Delete NUMELS elements from the specified gap array, starting at FROM. */
  645.  
  646. static void
  647. gap_array_delete_els (Gap_Array *ga, int from, int numdel)
  648. {
  649.   int to = from + numdel;
  650.   int gapsize = ga->gapsize;
  651.  
  652.   assert (from >= 0);
  653.   assert (numdel >= 0);
  654.   assert (to <= ga->numels);
  655.  
  656.   /* Make sure the gap is somewhere in or next to what we are deleting.  */
  657.   if (to < ga->gap)
  658.     gap_array_move_gap (ga, to);
  659.   if (from > ga->gap)
  660.     gap_array_move_gap (ga, from);
  661.  
  662.   /* Relocate all markers pointing into the new, larger gap
  663.      to point at the end of the text before the gap.  */
  664.   gap_array_adjust_markers (ga, to + gapsize, to + gapsize,
  665.                 - numdel - gapsize);
  666.  
  667.   ga->gapsize += numdel;
  668.   ga->numels -= numdel;
  669.   ga->gap = from;
  670. }
  671.  
  672. static Gap_Array_Marker *
  673. gap_array_make_marker (Gap_Array *ga, int pos)
  674. {
  675.   Gap_Array_Marker *m;
  676.  
  677.   assert (pos >= 0 && pos <= ga->numels);
  678.   if (gap_array_marker_freelist)
  679.     {
  680.       m = gap_array_marker_freelist;
  681.       gap_array_marker_freelist = gap_array_marker_freelist->next;
  682.     }
  683.   else
  684.     m = (Gap_Array_Marker *) xmalloc (sizeof (*m));
  685.  
  686.   m->pos = GAP_ARRAY_ARRAY_TO_MEMORY_POS (ga, pos);
  687.   m->next = ga->markers;
  688.   ga->markers = m;
  689.   return m;
  690. }
  691.  
  692. static void
  693. gap_array_delete_marker (Gap_Array *ga, Gap_Array_Marker *m)
  694. {
  695.   Gap_Array_Marker *p, *prev;
  696.  
  697.   for (prev = 0, p = ga->markers; p && p != m; prev = p, p = p->next)
  698.     ;
  699.   assert (p);
  700.   if (prev)
  701.     prev->next = p->next;
  702.   else
  703.     ga->markers = p->next;
  704.   m->next = gap_array_marker_freelist;
  705.   m->pos = 0xDEADBEEF; /* -559038737 as an int */
  706.   gap_array_marker_freelist = m;
  707. }
  708.  
  709. static void
  710. gap_array_delete_all_markers (Gap_Array *ga)
  711. {
  712.   Gap_Array_Marker *p, *next;
  713.  
  714.   for (p = ga->markers; p; p = next)
  715.     {
  716.       next = p->next;
  717.       p->next = gap_array_marker_freelist;
  718.       p->pos = 0xDEADBEEF; /* -559038737 as an int */
  719.       gap_array_marker_freelist = p;
  720.     }
  721. }
  722.  
  723. static void
  724. gap_array_move_marker (Gap_Array *ga, Gap_Array_Marker *m, int pos)
  725. {
  726.   assert (pos >= 0 && pos <= ga->numels);
  727.   m->pos = GAP_ARRAY_ARRAY_TO_MEMORY_POS (ga, pos);
  728. }
  729.  
  730. #define gap_array_marker_pos(ga, m) \
  731.   GAP_ARRAY_MEMORY_TO_ARRAY_POS (ga, (m)->pos)
  732.  
  733. static Gap_Array *
  734. make_gap_array (int elsize)
  735. {
  736.   Gap_Array *ga = (Gap_Array *) xmalloc (sizeof(*ga));
  737.   memset (ga, 0, sizeof(*ga));
  738.   ga->elsize = elsize;
  739.   return ga;
  740. }
  741.  
  742. static void
  743. free_gap_array (Gap_Array *ga)
  744. {
  745.   if (ga->array)
  746.     xfree (ga->array);
  747.   gap_array_delete_all_markers (ga);
  748.   xfree (ga);
  749. }
  750.  
  751.  
  752. /************************************************************************/
  753. /*                       Extent list primitives                         */
  754. /************************************************************************/
  755.  
  756. /* A list of extents is maintained as a double gap array: one gap array
  757.    is ordered by start index (the "display order") and the other is
  758.    ordered by end index (the "e-order").  Note that positions in an
  759.    extent list should logically be conceived of as referring *to*
  760.    a particular extent (as is the norm in programs) rather than
  761.    sitting between two extents.  Note also that callers of these
  762.    functions should not be aware of the fact that the extent list is
  763.    implemented as an array, except for the fact that positions are
  764.    integers (this should be generalized to handle integers and linked
  765.    list equally well).
  766. */
  767.  
  768. /* Number of elements in an extent list */
  769. #define extent_list_num_els(el) GAP_ARRAY_NUM_ELS(el->start)
  770.  
  771. /* Return the position at which EXTENT is located in the specified extent
  772.    list (in the display order if ENDP is 0, in the e-order otherwise).
  773.    If the extent is not found, the position where the extent would
  774.    be inserted is returned.  If ENDP is 0, the insertion would go after
  775.    all other equal extents.  If ENDP is not 0, the insertion would go
  776.    before all other equal extents.  If FOUNDP is not 0, then whether
  777.    the extent was found will get written into it. */
  778.  
  779. static int
  780. extent_list_locate (Extent_List *el, EXTENT extent, int endp, int *foundp)
  781. {
  782.   Gap_Array *ga = endp ? el->end : el->start;
  783.   int left = 0, right = GAP_ARRAY_NUM_ELS (ga);
  784.   int oldfoundpos, foundpos;
  785.   int found;
  786.   EXTENT e;
  787.  
  788.   while (left != right)
  789.     {
  790.       /* RIGHT might not point to a valid extent (i.e. it's at the end
  791.      of the list), so NEWPOS must round down. */
  792.       unsigned int newpos = (left + right) >> 1;
  793.       e = EXTENT_GAP_ARRAY_AT (ga, newpos);
  794.       
  795.       if (endp ? EXTENT_E_LESS (e, extent) : EXTENT_LESS (e, extent))
  796.     left = newpos+1;
  797.       else
  798.     right = newpos;
  799.     }
  800.  
  801.   /* Now we're at the beginning of all equal extents. */
  802.   found = 0;
  803.   oldfoundpos = foundpos = left;
  804.   while (foundpos < GAP_ARRAY_NUM_ELS (ga))
  805.     {
  806.       e = EXTENT_GAP_ARRAY_AT (ga, foundpos);
  807.       if (e == extent)
  808.     {
  809.       found = 1;
  810.       break;
  811.     }
  812.       if (!EXTENT_EQUAL (e, extent))
  813.     break;
  814.       foundpos++;
  815.     }
  816.   if (foundp)
  817.     *foundp = found;
  818.   if (found || !endp)
  819.     return foundpos;
  820.   else
  821.     return oldfoundpos;
  822. }
  823.  
  824. /* Return the position of the first extent that begins at or after POS
  825.    (or ends at or after POS, if ENDP is not 0).
  826.  
  827.    An out-of-range value for POS is allowed, and guarantees that the
  828.    position at the beginning or end of the extent list is returned. */
  829.  
  830. static int
  831. extent_list_locate_from_pos (Extent_List *el, Memind pos, int endp)
  832. {
  833.   struct extent fake_extent;
  834.   /*
  835.  
  836.    Note that if we search for [POS, POS], then we get the following:
  837.  
  838.    -- if ENDP is 0, then all extents whose start position is <= POS
  839.       lie before the returned position, and all extents whose start
  840.       position is > POS lie at or after the returned position.
  841.  
  842.    -- if ENDP is not 0, then all extents whose end position is < POS
  843.       lie before the returned position, and all extents whose end
  844.       position is >= POS lie at or after the returned position.
  845.  
  846.    */
  847.   set_extent_start (&fake_extent, endp ? pos : pos-1);
  848.   set_extent_end (&fake_extent, endp ? pos : pos-1);
  849.   return extent_list_locate (el, &fake_extent, endp, 0);
  850. }
  851.  
  852. /* Return the extent at POS. */
  853.  
  854. static EXTENT
  855. extent_list_at (Extent_List *el, Memind pos, int endp)
  856. {
  857.   Gap_Array *ga = endp ? el->end : el->start;
  858.  
  859.   assert (pos >= 0 && pos < GAP_ARRAY_NUM_ELS (ga));
  860.   return EXTENT_GAP_ARRAY_AT (ga, pos);
  861. }
  862.  
  863. /* Insert an extent into an extent list. */
  864.  
  865. static void
  866. extent_list_insert (Extent_List *el, EXTENT extent)
  867. {
  868.   int pos, foundp;
  869.  
  870.   pos = extent_list_locate (el, extent, 0, &foundp);
  871.   assert (!foundp);
  872.   gap_array_insert_els (el->start, pos, &extent, 1);
  873.   pos = extent_list_locate (el, extent, 1, &foundp);
  874.   assert (!foundp);
  875.   gap_array_insert_els (el->end, pos, &extent, 1);
  876. }
  877.  
  878. /* Delete an extent from an extent list. */
  879.  
  880. static void
  881. extent_list_delete (Extent_List *el, EXTENT extent)
  882. {
  883.   int pos, foundp;
  884.  
  885.   pos = extent_list_locate (el, extent, 0, &foundp);
  886.   assert (foundp);
  887.   gap_array_delete_els (el->start, pos, 1);
  888.   pos = extent_list_locate (el, extent, 1, &foundp);
  889.   assert (foundp);
  890.   gap_array_delete_els (el->end, pos, 1);
  891. }
  892.  
  893. static Extent_List_Marker *
  894. extent_list_make_marker (Extent_List *el, int pos, int endp)
  895. {
  896.   Extent_List_Marker *m;
  897.  
  898.   if (extent_list_marker_freelist)
  899.     {
  900.       m = extent_list_marker_freelist;
  901.       extent_list_marker_freelist = extent_list_marker_freelist->next;
  902.     }
  903.   else
  904.     m = (Extent_List_Marker *) xmalloc (sizeof (*m));
  905.  
  906.   m->m = gap_array_make_marker (endp ? el->end : el->start, pos);
  907.   m->endp = endp;
  908.   m->next = el->markers;
  909.   el->markers = m;
  910.   return m;
  911. }
  912.  
  913. #define extent_list_move_marker(el, mkr, pos) \
  914.   gap_array_move_marker((mkr)->endp ? (el)->end : (el)->start, (mkr)->m, pos)
  915.  
  916. static void
  917. extent_list_delete_marker (Extent_List *el, Extent_List_Marker *m)
  918. {
  919.   Extent_List_Marker *p, *prev;
  920.  
  921.   for (prev = 0, p = el->markers; p && p != m; prev = p, p = p->next)
  922.     ;
  923.   assert (p);
  924.   if (prev)
  925.     prev->next = p->next;
  926.   else
  927.     el->markers = p->next;
  928.   m->next = extent_list_marker_freelist;
  929.   extent_list_marker_freelist = m;
  930.   gap_array_delete_marker (m->endp ? el->end : el->start, m->m);
  931. }
  932.  
  933. #define extent_list_marker_pos(el, mkr) \
  934.   gap_array_marker_pos ((mkr)->endp ? (el)->end : (el)->start, (mkr)->m)
  935.  
  936. static Extent_List *
  937. make_extent_list (void)
  938. {
  939.   Extent_List *el = (Extent_List *) xmalloc (sizeof(*el));
  940.   el->start = make_gap_array (sizeof(EXTENT));
  941.   el->end = make_gap_array (sizeof(EXTENT));
  942.   el->markers = 0;
  943.   return el;
  944. }
  945.  
  946. static void
  947. free_extent_list (Extent_List *el)
  948. {
  949.   free_gap_array (el->start);
  950.   free_gap_array (el->end);
  951.   xfree (el);
  952. }
  953.  
  954.  
  955. /************************************************************************/
  956. /*                       Auxiliary extent structure                     */
  957. /************************************************************************/
  958.  
  959. static Lisp_Object mark_extent_auxiliary (Lisp_Object obj,
  960.                       void (*markobj) (Lisp_Object));
  961. DEFINE_LRECORD_IMPLEMENTATION ("extent-auxiliary", extent_auxiliary,
  962.                                mark_extent_auxiliary, 0, 0, 0, 0,
  963.                    struct extent_auxiliary);
  964.  
  965. static Lisp_Object
  966. mark_extent_auxiliary (Lisp_Object obj, void (*markobj) (Lisp_Object))
  967. {
  968.   struct extent_auxiliary *data =
  969.     (struct extent_auxiliary *) XEXTENT_AUXILIARY (obj);
  970.   ((markobj) (data->begin_glyph));
  971.   ((markobj) (data->end_glyph));
  972.   ((markobj) (data->parent));
  973.   /* data->children is a list so it should be returned rather
  974.      than recursed on */
  975.   return (data->children);
  976. }
  977.  
  978. void
  979. allocate_extent_aux_struct (EXTENT ext)
  980. {
  981.   Lisp_Object extent_aux = Qnil;
  982.   struct extent_auxiliary *data =
  983.     alloc_lcrecord (sizeof (struct extent_auxiliary),
  984.             lrecord_extent_auxiliary);
  985.  
  986.   copy_lcrecord (data, &extent_auxiliary_defaults);
  987.   XSETEXTENT_AUXILIARY (extent_aux, data);
  988.   ext->plist = Fcons (extent_aux, ext->plist);
  989.   ext->flags.has_aux = 1;
  990. }
  991.  
  992.  
  993. /************************************************************************/
  994. /*                    Buffer/string extent primitives                   */
  995. /************************************************************************/
  996.  
  997. /* The functions in this section are the ONLY ones that should know
  998.    about the internal implementation of the extent lists.  Other functions
  999.    should only know that there are two orderings on extents, the "display"
  1000.    order (sorted by start position, basically) and the e-order (sorted
  1001.    by end position, basically), and that certain operations are provided
  1002.    to manipulate the list. */
  1003.  
  1004. /* ------------------------------- */
  1005. /*        basic primitives         */
  1006. /* ------------------------------- */
  1007.  
  1008. static Lisp_Object
  1009. decode_extent_object (Lisp_Object object)
  1010. {
  1011.   if (NILP (object))
  1012.     XSETBUFFER (object, current_buffer);
  1013.   else
  1014.     CHECK_LIVE_BUFFER_OR_STRING (object, 0);
  1015.   return object;
  1016. }  
  1017.  
  1018. static void
  1019. strings_not_supported (void)
  1020. {
  1021.   error ("Extents over strings not currently supported");
  1022. }
  1023.  
  1024. EXTENT
  1025. extent_ancestor_1 (EXTENT e)
  1026. {
  1027.   while (e->flags.has_parent)
  1028.     {
  1029.       /* There should be no circularities except in case of a logic
  1030.      error somewhere in the extent code */
  1031.       e = XEXTENT (XEXTENT_AUXILIARY (XCAR (e->plist))->parent);
  1032.     }
  1033.   return e;
  1034. }
  1035.  
  1036. /* Given a string or buffer, return its extent list */
  1037.  
  1038. static Extent_List *
  1039. extent_object_extent_list (Lisp_Object object)
  1040. {
  1041.   if (STRINGP (object))
  1042.     {
  1043.       strings_not_supported ();
  1044.       return 0;
  1045.     }
  1046.   else
  1047.     {
  1048.       assert (BUFFERP (object));
  1049.       return XBUFFER (object)->extents;
  1050.     }
  1051. }
  1052.  
  1053. /* Retrieve the extent list that an extent is a member of */
  1054.  
  1055. #define extent_extent_list(e) extent_object_extent_list (extent_object (e))
  1056.  
  1057. /* ------------------------------- */
  1058. /*        stack of extents         */
  1059. /* ------------------------------- */
  1060.  
  1061. #ifdef ERROR_CHECK_EXTENTS
  1062.  
  1063. void
  1064. sledgehammer_extent_check (Lisp_Object object)
  1065. {
  1066.   int i;
  1067.   int endp;
  1068.   Extent_List *el = extent_object_extent_list (object);
  1069.   struct buffer *buf = 0;
  1070.  
  1071.   if (BUFFERP (object))
  1072.     buf = XBUFFER (object);
  1073.  
  1074.   for (endp = 0; endp < 2; endp++)
  1075.     for (i = 1; i < extent_list_num_els (el); i++)
  1076.       {
  1077.         EXTENT e1 = extent_list_at (el, i-1, endp);
  1078.     EXTENT e2 = extent_list_at (el, i, endp);
  1079.     if (buf)
  1080.       {
  1081.         assert (extent_start (e1) <= buf->text.gpt ||
  1082.             extent_start (e1) > buf->text.gpt + buf->text.gap_size);
  1083.         assert (extent_end (e1) <= buf->text.gpt ||
  1084.             extent_end (e1) > buf->text.gpt + buf->text.gap_size);
  1085.       }
  1086.     assert (extent_start (e1) <= extent_end (e1));
  1087.     assert (endp ? (EXTENT_E_LESS_EQUAL (e1, e2)) :
  1088.                (EXTENT_LESS_EQUAL (e1, e2)));
  1089.       }
  1090. }
  1091.  
  1092. #endif
  1093.  
  1094. static Stack_Of_Extents *
  1095. extent_object_stack_of_extents (Lisp_Object object)
  1096. {
  1097.   if (STRINGP (object))
  1098.     {
  1099.       /* Maybe not all strings will have a stack of extents.  In such
  1100.      a case, we need to keep a cache of stacks of extents for the
  1101.      strings that don't have them, and return such a cache now.
  1102.      Returning 0 is not allowed. */
  1103.       strings_not_supported ();
  1104.       return 0;
  1105.     }
  1106.   else
  1107.     {
  1108.       assert (BUFFERP (object));
  1109.       return XBUFFER (object)->soe;
  1110.     }
  1111. }
  1112.  
  1113. /* #define SOE_DEBUG */
  1114.  
  1115. #ifdef SOE_DEBUG
  1116.  
  1117. static char *print_extent_1 (char *buf, Lisp_Object extent);
  1118.  
  1119. static void
  1120. print_extent_2 (EXTENT e)
  1121. {
  1122.   Lisp_Object extent;
  1123.   char buf[200];
  1124.  
  1125.   XSETEXTENT (extent, e);
  1126.   print_extent_1 (buf, extent);
  1127.   printf ("%s", buf);
  1128. }
  1129.  
  1130. static void
  1131. soe_dump (Lisp_Object obj)
  1132. {
  1133.   int i;
  1134.   Stack_Of_Extents *soe = extent_object_stack_of_extents (obj);
  1135.   Extent_List *sel;
  1136.   int endp;
  1137.  
  1138.   sel = soe->extents;
  1139.   printf ("SOE pos is %d (memind %d)\n",
  1140.       extent_object_memind_to_bytind (obj, soe->pos),
  1141.       soe->pos);
  1142.   for (endp = 0; endp < 2; endp++)
  1143.     {
  1144.       printf (endp ? "SOE end:" : "SOE start:");
  1145.       for (i = 0; i < extent_list_num_els (sel); i++)
  1146.     {
  1147.       EXTENT e = extent_list_at (sel, i, endp);
  1148.       printf ("\t");
  1149.       print_extent_2 (e);
  1150.     }
  1151.       printf ("\n");
  1152.     }
  1153.   printf ("\n");
  1154. }
  1155.  
  1156. #endif
  1157.  
  1158. /* Insert EXTENT into OBJ's stack of extents, if necessary. */
  1159.  
  1160. static void
  1161. soe_insert (Lisp_Object obj, EXTENT extent)
  1162. {
  1163.   Stack_Of_Extents *soe = extent_object_stack_of_extents (obj);
  1164.  
  1165. #ifdef SOE_DEBUG
  1166.   printf ("Inserting into SOE: ");
  1167.   print_extent_2 (extent);
  1168.   printf ("\n");
  1169. #endif
  1170.   if (soe->pos < extent_start (extent) || soe->pos > extent_end (extent))
  1171.     {
  1172. #ifdef SOE_DEBUG
  1173.       printf ("(not needed)\n\n");
  1174. #endif
  1175.       return;
  1176.     }
  1177.   extent_list_insert (soe->extents, extent);
  1178. #ifdef SOE_DEBUG
  1179.   printf ("SOE afterwards is:\n");
  1180.   soe_dump (obj);
  1181. #endif
  1182. }
  1183.  
  1184. /* Delete EXTENT from OBJ's stack of extents, if necessary. */
  1185.  
  1186. static void
  1187. soe_delete (Lisp_Object obj, EXTENT extent)
  1188. {
  1189.   Stack_Of_Extents *soe = extent_object_stack_of_extents (obj);
  1190.  
  1191. #ifdef SOE_DEBUG
  1192.   printf ("Deleting from SOE: ");
  1193.   print_extent_2 (extent);
  1194.   printf ("\n");
  1195. #endif
  1196.   if (soe->pos < extent_start (extent) || soe->pos > extent_end (extent))
  1197.     {
  1198. #ifdef SOE_DEBUG
  1199.       printf ("(not needed)\n\n");
  1200. #endif
  1201.       return;
  1202.     }
  1203.   extent_list_delete (soe->extents, extent);
  1204. #ifdef SOE_DEBUG
  1205.   printf ("SOE afterwards is:\n");
  1206.   soe_dump (obj);
  1207. #endif
  1208. }
  1209.  
  1210. /* Move BUF's stack of extents to lie over the specified position. */
  1211.  
  1212. static void
  1213. soe_move (Lisp_Object obj, Memind pos)
  1214. {
  1215.   Stack_Of_Extents *soe = extent_object_stack_of_extents (obj);
  1216.   Extent_List *sel = soe->extents;
  1217.   int numsoe = extent_list_num_els (sel);
  1218.   Extent_List *bel = extent_object_extent_list (obj);
  1219.   int direction;
  1220.   int endp;
  1221.  
  1222. #ifdef SOE_DEBUG
  1223.   printf ("Moving SOE from %d (memind %d) to %d (memind %d)\n",
  1224.       extent_object_memind_to_bytind (obj, soe->pos), soe->pos,
  1225.       extent_object_memind_to_bytind (obj, pos), pos);
  1226. #endif
  1227.   if (soe->pos < pos)
  1228.     {
  1229.       direction = 1;
  1230.       endp = 0;
  1231.     }
  1232.   else if (soe->pos > pos)
  1233.     {
  1234.       direction = -1;
  1235.       endp = 1;
  1236.     }
  1237.   else
  1238.     {
  1239. #ifdef SOE_DEBUG
  1240.       printf ("(not needed)\n\n");
  1241. #endif
  1242.       return;
  1243.     }
  1244.  
  1245.   /* For DIRECTION = 1: Any extent that overlaps POS is either in the
  1246.      SOE (if the extent starts at or before SOE->POS) or is greater
  1247.      (in the display order) than any extent in the SOE (if it starts
  1248.      after SOE->POS).
  1249.  
  1250.      For DIRECTION = -1: Any extent that overlaps POS is either in the
  1251.      SOE (if the extent ends at or after SOE->POS) or is less (in the
  1252.      e-order) than any extent in the SOE (if it ends before SOE->POS).
  1253.  
  1254.      We proceed in two stages:
  1255.  
  1256.      1) delete all extents in the SOE that don't overlap POS.
  1257.      2) insert all extents into the SOE that start (or end, when
  1258.         DIRECTION = -1) in (SOE->POS, POS] and that overlap
  1259.     POS. (Don't include SOE->POS in the range because those
  1260.     extents would already be in the SOE.)
  1261.    */
  1262.  
  1263.   /* STAGE 1. */
  1264.  
  1265.   if (numsoe > 0)
  1266.     {
  1267.       /* Delete all extents in the SOE that don't overlap POS.
  1268.      This is all extents that end before (or start after,
  1269.      if DIRECTION = -1) POS.
  1270.        */
  1271.  
  1272.       /* Deleting extents from the SOE is tricky because it changes
  1273.      the positions of extents.  If we are deleting in the forward
  1274.      direction we have to call extent_list_at() on the same position
  1275.      over and over again because positions after the deleted element
  1276.      get shifted back by 1.  To make life simplest, we delete forward
  1277.      irrespective of DIRECTION.
  1278.        */
  1279.       int start, end;
  1280.       int i;
  1281.  
  1282.       if (direction > 0)
  1283.     {
  1284.       start = 0;
  1285.       end = extent_list_locate_from_pos (sel, pos, 1);
  1286.     }
  1287.       else
  1288.     {
  1289.       start = extent_list_locate_from_pos (sel, pos+1, 0);
  1290.       end = numsoe;
  1291.     }
  1292.  
  1293.       for (i = start; i < end; i++)
  1294.     extent_list_delete (sel, extent_list_at (sel, start /* see above */,
  1295.                          !endp));
  1296.     }
  1297.  
  1298.   /* STAGE 2. */
  1299.  
  1300.   {
  1301.     int start_pos;
  1302.  
  1303.     if (direction < 0)
  1304.       start_pos = extent_list_locate_from_pos (bel, soe->pos, endp) - 1;
  1305.     else
  1306.       start_pos = extent_list_locate_from_pos (bel, soe->pos + 1, endp);
  1307.  
  1308.     for (; start_pos >= 0 && start_pos < extent_list_num_els (bel);
  1309.      start_pos += direction)
  1310.       {
  1311.     EXTENT e = extent_list_at (bel, start_pos, endp);
  1312.     if ((direction > 0) ?
  1313.         (extent_start (e) > pos) :
  1314.         (extent_end (e) < pos))
  1315.       break; /* All further extents lie on the far side of POS
  1316.             and thus can't overlap. */
  1317.     if ((direction > 0) ?
  1318.         (extent_end (e) >= pos) :
  1319.         (extent_start (e) <= pos))
  1320.       extent_list_insert (sel, e);
  1321.       }
  1322.   }
  1323.  
  1324.   soe->pos = pos;
  1325. #ifdef SOE_DEBUG
  1326.   printf ("SOE afterwards is:\n");
  1327.   soe_dump (obj);
  1328. #endif
  1329. }
  1330.  
  1331. static struct stack_of_extents *
  1332. make_soe (void)
  1333. {
  1334.   struct stack_of_extents *soe = (struct stack_of_extents *)
  1335.     xmalloc (sizeof (*soe));
  1336.   soe->extents = make_extent_list ();
  1337.   soe->pos = 0;
  1338.   return soe;
  1339. }
  1340.  
  1341. static void
  1342. free_soe (struct stack_of_extents *soe)
  1343. {
  1344.   free_extent_list (soe->extents);
  1345.   xfree (soe);
  1346. }
  1347.  
  1348. /* ------------------------------- */
  1349. /*        other primitives         */
  1350. /* ------------------------------- */
  1351.  
  1352. /* Return the start (endp == 0) or end (endp == 1) of an extent as
  1353.    a byte index.  If you want the value as a memory index, use
  1354.    extent_endpoint().  If you want the value as a buffer position,
  1355.    use extent_endpoint_bufpos(). */
  1356.  
  1357. static Bytind 
  1358. extent_endpoint_bytind (EXTENT extent, int endp)
  1359. {
  1360.   assert (EXTENT_LIVE_P (extent));
  1361.   assert (!extent_detached_p (extent));
  1362.   {
  1363.     Memind i = (endp) ? (extent_end (extent)) :
  1364.       (extent_start (extent));
  1365.     Lisp_Object obj = extent_object (extent);
  1366.     return extent_object_memind_to_bytind (obj, i);
  1367.   }
  1368. }
  1369.  
  1370. static Bufpos
  1371. extent_endpoint_bufpos (EXTENT extent, int endp)
  1372. {
  1373.   assert (EXTENT_LIVE_P (extent));
  1374.   assert (!extent_detached_p (extent));
  1375.   {
  1376.     Memind i = (endp) ? (extent_end (extent)) :
  1377.       (extent_start (extent));
  1378.     Lisp_Object obj = extent_object (extent);
  1379.     return extent_object_memind_to_bufpos (obj, i);
  1380.   }
  1381. }
  1382.  
  1383. /* A change to an extent occurred that will change the display, so
  1384.    notify redisplay.  Maybe also recurse over all the extent's
  1385.    descendants. */
  1386.  
  1387. static void
  1388. extent_changed_for_redisplay (EXTENT extent, int descendants_too)
  1389. {
  1390.   Lisp_Object object;
  1391.   struct buffer *b;
  1392.   Lisp_Object rest;
  1393.  
  1394.   /* we could easily encounter a detached extent while traversing the
  1395.      children, but we should never be able to encounter a dead extent. */
  1396.   assert (EXTENT_LIVE_P (extent));
  1397.  
  1398.   if (descendants_too)
  1399.     {
  1400.       /* first mark all of the extent's children.  We will lose big-time
  1401.      if there are any circularities here, so we sure as hell better
  1402.      ensure that there aren't. */
  1403.       for (rest = extent_children (extent); !NILP (rest);
  1404.        rest = XCDR (rest))
  1405.     extent_changed_for_redisplay (XEXTENT (XCAR (rest)), 1);
  1406.     }
  1407.  
  1408.   /* now mark the extent itself. */
  1409.   
  1410.   object = extent_object (extent);
  1411.  
  1412.   if (!BUFFERP (object) || extent_detached_p (extent))
  1413.     /* #### Can changes to string extents affect redisplay?
  1414.        I will have to think about this.  What about string glyphs?
  1415.        Things in the modeline? etc. */
  1416.     return;
  1417.  
  1418.   b = XBUFFER (object);
  1419.   BUF_FACECHANGE (b)++;
  1420.   MARK_EXTENTS_CHANGED;
  1421.   buffer_extent_signal_changed_region (b,
  1422.                        extent_endpoint_bufpos (extent, 0),
  1423.                        extent_endpoint_bufpos (extent, 1));
  1424. }
  1425.  
  1426. /* A change to an extent occurred that will might affect redisplay.
  1427.    This is called when properties such as the endpoints, the layout,
  1428.    or the priority changes.  Redisplay will be affected only if
  1429.    the extent has any displayable attributes. */
  1430.  
  1431. static void
  1432. extent_maybe_changed_for_redisplay (EXTENT extent, int descendants_too)
  1433. {
  1434.   EXTENT anc = extent_ancestor (extent);
  1435.   if (!NILP (extent_face (anc)) || !NILP (extent_begin_glyph (anc)) ||
  1436.       !NILP (extent_end_glyph (anc)) || extent_highlight_p (anc) ||
  1437.       extent_invisible_p (anc) || extent_intangible_p (anc))
  1438.     extent_changed_for_redisplay (extent, descendants_too);
  1439. }
  1440.  
  1441. static EXTENT
  1442. make_extent_detached (Lisp_Object object)
  1443. {
  1444.   EXTENT extent = make_extent ();
  1445.  
  1446.   assert (NILP (object) || STRINGP (object) ||
  1447.       (BUFFERP (object) && BUFFER_LIVE_P (XBUFFER (object))));
  1448.   extent_object (extent) = object;
  1449.   return extent;
  1450. }
  1451.  
  1452. static EXTENT
  1453. real_extent_at_forward (Extent_List *el, int pos, int endp)
  1454. {
  1455.   for (; pos < extent_list_num_els (el); pos++)
  1456.     {
  1457.       EXTENT e = extent_list_at (el, pos, endp);
  1458.       if (!extent_internal_p (e))
  1459.     return e;
  1460.     }
  1461.   return 0;
  1462. }
  1463.  
  1464. static EXTENT
  1465. real_extent_at_backward (Extent_List *el, int pos, int endp)
  1466. {
  1467.   for (; pos >= 0; pos--)
  1468.     {
  1469.       EXTENT e = extent_list_at (el, pos, endp);
  1470.       if (!extent_internal_p (e))
  1471.     return e;
  1472.     }
  1473.   return 0;
  1474. }
  1475.  
  1476. static EXTENT
  1477. extent_first (Lisp_Object obj)
  1478. {
  1479.   return real_extent_at_forward (extent_object_extent_list (obj), 0, 0);
  1480. }
  1481.  
  1482. #ifdef DEBUG_XEMACS
  1483. static EXTENT
  1484. extent_e_first (Lisp_Object obj)
  1485. {
  1486.   return real_extent_at_forward (extent_object_extent_list (obj), 0, 1);
  1487. }
  1488. #endif
  1489.  
  1490. static EXTENT
  1491. extent_next (EXTENT e)
  1492. {
  1493.   Extent_List *el = extent_extent_list (e);
  1494.   int foundp;
  1495.   int pos;
  1496.  
  1497.   pos = extent_list_locate (el, e, 0, &foundp);
  1498.   assert (foundp);
  1499.   return real_extent_at_forward (el, pos+1, 0);
  1500. }
  1501.  
  1502. #ifdef DEBUG_XEMACS
  1503. static EXTENT
  1504. extent_e_next (EXTENT e)
  1505. {
  1506.   Extent_List *el = extent_extent_list (e);
  1507.   int foundp;
  1508.   int pos;
  1509.  
  1510.   pos = extent_list_locate (el, e, 1, &foundp);
  1511.   assert (foundp);
  1512.   return real_extent_at_forward (el, pos+1, 1);
  1513. }
  1514. #endif
  1515.  
  1516. static EXTENT
  1517. extent_last (Lisp_Object obj)
  1518. {
  1519.   Extent_List *el = extent_object_extent_list (obj);
  1520.   return real_extent_at_backward (el, extent_list_num_els (el) - 1, 0);
  1521. }
  1522.  
  1523. #ifdef DEBUG_XEMACS
  1524. static EXTENT
  1525. extent_e_last (Lisp_Object obj)
  1526. {
  1527.   Extent_List *el = extent_object_extent_list (obj);
  1528.   return real_extent_at_backward (el, extent_list_num_els (el) - 1, 1);
  1529. }
  1530. #endif
  1531.  
  1532. static EXTENT
  1533. extent_previous (EXTENT e)
  1534. {
  1535.   Extent_List *el = extent_extent_list (e);
  1536.   int foundp;
  1537.   int pos;
  1538.  
  1539.   pos = extent_list_locate (el, e, 0, &foundp);
  1540.   assert (foundp);
  1541.   return real_extent_at_backward (el, pos-1, 0);
  1542. }
  1543.  
  1544. #ifdef DEBUG_XEMACS
  1545. static EXTENT
  1546. extent_e_previous (EXTENT e)
  1547. {
  1548.   Extent_List *el = extent_extent_list (e);
  1549.   int foundp;
  1550.   int pos;
  1551.  
  1552.   pos = extent_list_locate (el, e, 1, &foundp);
  1553.   assert (foundp);
  1554.   return real_extent_at_backward (el, pos-1, 1);
  1555. }
  1556. #endif
  1557.  
  1558. static void
  1559. extent_attach (EXTENT extent)
  1560. {
  1561.   Extent_List *el = extent_extent_list (extent);
  1562.  
  1563.   extent_list_insert (el, extent);
  1564.   soe_insert (extent_object (extent), extent);
  1565.   /* only this extent changed */
  1566.   extent_maybe_changed_for_redisplay (extent, 0);
  1567. }
  1568.  
  1569. static void
  1570. extent_detach (EXTENT extent)
  1571.   Extent_List *el = extent_extent_list (extent);
  1572.  
  1573.   /* call this before messing with the extent. */
  1574.   extent_maybe_changed_for_redisplay (extent, 0);
  1575.   extent_list_delete (el, extent);
  1576.   soe_delete (extent_object (extent), extent);
  1577.   set_extent_start (extent, 0);
  1578.   set_extent_end (extent, 0);
  1579. }
  1580.  
  1581. /* ------------------------------- */
  1582. /*        map-extents et al.       */
  1583. /* ------------------------------- */
  1584.  
  1585. /* Returns true iff map_extents() would visit the given extent.
  1586.    See the comments at map_extents() for info on the overlap rule.
  1587.    Assumes that all validation on the extent and buffer positions has
  1588.    already been performed (see Fextent_in_region_p ()).
  1589.  */
  1590. static int
  1591. extent_in_region_p (EXTENT extent, Bytind from, Bytind to,
  1592.             unsigned int flags)
  1593. {
  1594.   Lisp_Object obj = extent_object (extent);
  1595.   Endpoint_Index start, end, exs, exe;
  1596.   int start_open, end_open;
  1597.   unsigned int all_extents_flags = flags & ME_ALL_EXTENTS_MASK;
  1598.   unsigned int in_region_flags = flags & ME_IN_REGION_MASK;
  1599.   int retval;
  1600.  
  1601.   /* A zero-length region is treated as closed-closed. */
  1602.   if (from == to)
  1603.     {
  1604.       flags |= ME_END_CLOSED;
  1605.       flags &= ~ME_START_OPEN;
  1606.     }
  1607.  
  1608.   switch (all_extents_flags)
  1609.     {
  1610.     case ME_ALL_EXTENTS_CLOSED:
  1611.       start_open = end_open = 0; break;
  1612.     case ME_ALL_EXTENTS_OPEN:
  1613.       start_open = end_open = 1; break;
  1614.     case ME_ALL_EXTENTS_CLOSED_OPEN:
  1615.       start_open = 0; end_open = 1; break;
  1616.     case ME_ALL_EXTENTS_OPEN_CLOSED:
  1617.       start_open = 1; end_open = 0; break;
  1618.     default:
  1619.       start_open = extent_start_open_p (extent);
  1620.       end_open = extent_end_open_p (extent);
  1621.       break;
  1622.     }
  1623.  
  1624.   /* So is a zero-length extent. */
  1625.   if (extent_start (extent) == extent_end (extent))
  1626.     start_open = end_open = 0;
  1627.  
  1628.   start = extent_object_bytind_to_startind (obj, from, flags & ME_START_OPEN);
  1629.   end = extent_object_bytind_to_endind (obj, to, ! (flags & ME_END_CLOSED));
  1630.   exs = memind_to_startind (extent_start (extent), start_open);
  1631.   exe = memind_to_endind (extent_end (extent), end_open);
  1632.  
  1633.   /* It's easy to determine whether an extent lies *outside* the
  1634.      region -- just determine whether it's completely before
  1635.      or completely after the region.  Reject all such extents, so
  1636.      we're now left with only the extents that overlap the region.
  1637.    */
  1638.  
  1639.   if (exs > end || exe < start)
  1640.     return 0;
  1641.  
  1642.   /* See if any further restrictions are called for. */
  1643.   switch (in_region_flags)
  1644.     {
  1645.     case ME_START_IN_REGION:
  1646.       retval = start <= exs && exs <= end; break;
  1647.     case ME_END_IN_REGION:
  1648.       retval = start <= exe && exe <= end; break;
  1649.     case ME_START_AND_END_IN_REGION:
  1650.       retval = start <= exs && exe <= end; break;
  1651.     case ME_START_OR_END_IN_REGION:
  1652.       retval = (start <= exs && exs <= end) || (start <= exe && exe <= end);
  1653.       break;
  1654.     default:
  1655.       retval = 1; break;
  1656.     }
  1657.   return flags & ME_NEGATE_IN_REGION ? !retval : retval;
  1658. }
  1659.  
  1660. struct map_extents_struct
  1661. {
  1662.   Extent_List *el;
  1663.   Extent_List_Marker *mkr;
  1664.   EXTENT range;
  1665. };
  1666.  
  1667. static Lisp_Object
  1668. map_extents_unwind (Lisp_Object obj)
  1669. {
  1670.   struct map_extents_struct *closure = 
  1671.     (struct map_extents_struct *) get_opaque_ptr (obj);
  1672.   if (closure->range)
  1673.     extent_detach (closure->range);
  1674.   if (closure->mkr)
  1675.     extent_list_delete_marker (closure->el, closure->mkr);
  1676.   return Qnil;
  1677. }
  1678.  
  1679. /* This is the guts of `map-extents' and the other functions that
  1680.    map over extents.  In theory the operation of this function is
  1681.    simple: just figure out what extents we're mapping over, and
  1682.    call the function on each one of them in the range.  Unfortunately
  1683.    there are a wide variety of things that the mapping function
  1684.    might do, and we have to be very tricky to avoid getting messed
  1685.    up.  Furthermore, this function needs to be very fast (it is
  1686.    called multiple times every time text is inserted or deleted
  1687.    from a buffer), and so we can't always afford the overhead of
  1688.    dealing with all the possible things that the mapping function
  1689.    might do; thus, there are many flags that can be specified
  1690.    indicating what the mapping function might or might not do.
  1691.  
  1692.    The result of all this is that this is the most complicated
  1693.    function in this file.  Change it at your own risk!
  1694.  
  1695.    A potential simplification to the logic below is to determine
  1696.    all the extents that the mapping function should be called on
  1697.    before any calls are actually made and save them in an array.
  1698.    That introduces its own complications, however (the array
  1699.    needs to be marked for garbage-collection, and a static array
  1700.    cannot be used because map_extents() needs to be reentrant).
  1701.    Furthermore, the results might be a little less sensible than
  1702.    the logic below. */
  1703.  
  1704. static void
  1705. map_extents_bytind (Bytind from, Bytind to, emf fn, void *arg,
  1706.             Lisp_Object obj, EXTENT after, unsigned int flags)
  1707. {
  1708.   Memind st, en; /* range we're mapping over */
  1709.   EXTENT range = 0; /* extent for this, if ME_MIGHT_MODIFY_TEXT */
  1710.   Extent_List *el = 0; /* extent list we're iterating over */
  1711.   Extent_List_Marker *posm = 0; /* marker for extent list,
  1712.                    if ME_MIGHT_MODIFY_EXTENTS */
  1713.   /* count and struct for unwind-protect, if ME_MIGHT_THROW */
  1714.   int count = 0;
  1715.   struct map_extents_struct closure;
  1716.  
  1717. #ifdef ERROR_CHECK_EXTENTS
  1718.   assert (from <= to);
  1719.   assert (from >= extent_object_absolute_start (obj) &&
  1720.       from <= extent_object_absolute_limit (obj) &&
  1721.       to >= extent_object_absolute_start (obj) &&
  1722.       to <= extent_object_absolute_limit (obj));
  1723. #endif
  1724.  
  1725.   if (after)
  1726.     {
  1727.       assert (EQ (obj, extent_object (after)));
  1728.       assert (!extent_detached_p (after));
  1729.     }
  1730.  
  1731.   st = extent_object_bytind_to_memind (obj, from);
  1732.   en = extent_object_bytind_to_memind (obj, to);
  1733.  
  1734.   if (flags & ME_MIGHT_MODIFY_TEXT)
  1735.     {
  1736.       /* The mapping function might change the text in the buffer,
  1737.      so make an internal extent to hold the range we're mapping
  1738.      over. */
  1739.       range = make_extent_detached (obj);
  1740.       set_extent_start (range, st);
  1741.       set_extent_end (range, en);
  1742.       range->flags.start_open = flags & ME_START_OPEN;
  1743.       range->flags.end_open = !(flags & ME_END_CLOSED);
  1744.       range->flags.internal = 1;
  1745.       range->flags.detachable = 0;
  1746.       extent_attach (range);
  1747.     }
  1748.  
  1749.   if (flags & ME_MIGHT_THROW)
  1750.     {
  1751.       /* The mapping function might throw past us so we need to use an
  1752.      unwind_protect() to eliminate the internal extent and range
  1753.      that we use. */
  1754.       count = specpdl_depth ();
  1755.       closure.range = range;
  1756.       closure.mkr = 0;
  1757.       record_unwind_protect (map_extents_unwind,
  1758.                  make_opaque_ptr (&closure));
  1759.     }
  1760.  
  1761.   /* ---------- Figure out where we start and what direction
  1762.                 we move in.  This is the trickiest part of this
  1763.         function. ---------- */
  1764.  
  1765.   /* If ME_START_IN_REGION, ME_END_IN_REGION or ME_START_AND_END_IN_REGION
  1766.      was specified and ME_NEGATE_IN_REGION was not specified, our job
  1767.      is simple because of the presence of the display order and e-order.
  1768.      (Note that theoretically do something similar for
  1769.      ME_START_OR_END_IN_REGION, but that would require more trickiness
  1770.      than it's worth to avoid hitting the same extent twice.)
  1771.  
  1772.      In the general case, all the extents that overlap a range can be
  1773.      divided into two classes: those whose start position lies within
  1774.      the range (including the range's end but not including the
  1775.      range's start), and those that overlap the start position,
  1776.      i.e. those in the SOE for the start position.  Or equivalently,
  1777.      the extents can be divided into those whose end position lies
  1778.      within the range and those in the SOE for the end position.  Note
  1779.      that for this purpose we treat both the range and all extents in
  1780.      the buffer as closed on both ends.  If this is not what the ME_
  1781.      flags specified, then we've mapped over a few too many extents,
  1782.      but no big deal because extent_in_region_p() will filter them
  1783.      out.   Ideally, we could move the SOE to the closer of the range's
  1784.      two ends and work forwards or backwards from there.  However, in
  1785.      order to make the semantics of the AFTER argument work out, we
  1786.      have to always go in the same direction; so we choose to always
  1787.      move the SOE to the start position.
  1788.  
  1789.      When it comes time to do the SOE stage, we first call soe_move()
  1790.      so that the SOE gets set up.  Note that the SOE might get
  1791.      changed while we are mapping over its contents.  If we can
  1792.      guarantee that the SOE won't get moved to a new position, we
  1793.      simply need to put a marker in the SOE and we will track deletions
  1794.      and insertions of extents in the SOE.  If the SOE might get moved,
  1795.      however (this would happen as a result of a recursive invocation
  1796.      of map-extents or a call to a redisplay-type function), then
  1797.      trying to track its changes is hopeless, so we just keep a
  1798.      marker to the first (or last) extent in the SOE and use that as
  1799.      our bound.
  1800.  
  1801.      Finally, if DONT_USE_SOE is defined, we don't use the SOE at all
  1802.      and instead just map from the beginning of the buffer.  This is
  1803.      used for testing purposes and allows the SOE to be calculated
  1804.      using map_extents() instead of the other way around. */
  1805.  
  1806.   {
  1807.     int range_flag; /* ME_*_IN_REGION subset of flags */
  1808.     int do_soe_stage = 0; /* Are we mapping over the SOE? */
  1809.     /* Does the range stage map over start or end positions? */
  1810.     int range_endp;
  1811.     /* If type == 0, we include the start position in the range stage mapping.
  1812.        If type == 1, we exclude the start position in the range stage mapping.
  1813.        If type == 2, we begin at range_start_pos, an extent-list position.
  1814.      */
  1815.     int range_start_type = 0;
  1816.     int range_start_pos = 0;
  1817.     int stage;
  1818.  
  1819.     range_flag = flags & ME_IN_REGION_MASK;
  1820.     if ((range_flag == ME_START_IN_REGION ||
  1821.      range_flag == ME_START_AND_END_IN_REGION) &&
  1822.     !(flags & ME_NEGATE_IN_REGION))
  1823.       {
  1824.     /* map over start position in [range-start, range-end].  No SOE
  1825.        stage. */
  1826.     range_endp = 0;
  1827.       }
  1828.     else if (range_flag == ME_END_IN_REGION && !(flags & ME_NEGATE_IN_REGION))
  1829.       {
  1830.     /* map over end position in [range-start, range-end].  No SOE
  1831.        stage. */
  1832.     range_endp = 1;
  1833.       }
  1834.     else
  1835.       {
  1836.     /* Need to include the SOE extents. */
  1837. #ifdef DONT_USE_SOE
  1838.     /* Just brute-force it: start from the beginning. */
  1839.     range_endp = 0;
  1840.     range_start_type = 2;
  1841.     range_start_pos = 0;
  1842. #else
  1843.     Stack_Of_Extents *soe = extent_object_stack_of_extents (obj);
  1844.     int numsoe;
  1845.     
  1846.     /* Move the SOE to the closer end of the range.  This dictates
  1847.        whether we map over start positions or end positions. */
  1848.     range_endp = 0;
  1849.     soe_move (obj, st);
  1850.     numsoe = extent_list_num_els (soe->extents);
  1851.     if (numsoe)
  1852.       {
  1853.         if (flags & ME_MIGHT_MOVE_SOE)
  1854.           {
  1855.         int foundp;
  1856.         /* Can't map over SOE, so just extend range to cover the
  1857.            SOE. */
  1858.         EXTENT e = extent_list_at (soe->extents, 0, 0);
  1859.         range_start_pos =
  1860.           extent_list_locate (extent_object_extent_list (obj), e, 0,
  1861.                       &foundp);
  1862.         assert (foundp);
  1863.         range_start_type = 2;
  1864.           }
  1865.         else
  1866.           {
  1867.         /* We can map over the SOE. */
  1868.         do_soe_stage = 1;
  1869.         range_start_type = 1;
  1870.           }
  1871.       }
  1872.     else
  1873.       {
  1874.         /* No extents in the SOE to map over, so we act just as if
  1875.            ME_START_IN_REGION or ME_END_IN_REGION was specified.
  1876.            RANGE_ENDP already specified so no need to do anything else. */
  1877.       }
  1878.       }
  1879. #endif
  1880.       
  1881.   /* ---------- Now loop over the extents. ---------- */
  1882.  
  1883.     /* We combine the code for the two stages because much of it
  1884.        overlaps. */
  1885.     for (stage = 0; stage < 2; stage++)
  1886.       {
  1887.     int pos = 0; /* Position in extent list */
  1888.  
  1889.     /* First set up start conditions */
  1890.     if (stage == 0)
  1891.       { /* The SOE stage */
  1892.         if (!do_soe_stage)
  1893.           continue;
  1894.         el = extent_object_stack_of_extents (obj)->extents;
  1895.         /* We will always be looping over start extents here. */
  1896.         assert (!range_endp);
  1897.         pos = 0;
  1898.       }
  1899.     else
  1900.       { /* The range stage */
  1901.         el = extent_object_extent_list (obj);
  1902.         switch (range_start_type)
  1903.           {
  1904.           case 0:
  1905.         pos = extent_list_locate_from_pos (el, st, range_endp);
  1906.         break;
  1907.           case 1:
  1908.         pos = extent_list_locate_from_pos (el, st + 1, range_endp);
  1909.         break;
  1910.           case 2:
  1911.         pos = range_start_pos;
  1912.         break;
  1913.           }
  1914.       }
  1915.  
  1916.     if (flags & ME_MIGHT_MODIFY_EXTENTS)
  1917.       {
  1918.         /* Create a marker to track changes to the extent list */
  1919.         if (posm)
  1920.           /* Delete the marker used in the SOE stage. */
  1921.           extent_list_delete_marker
  1922.         (extent_object_stack_of_extents (obj)->extents, posm);
  1923.         posm = extent_list_make_marker (el, pos, range_endp);
  1924.         /* tell the unwind function about the marker. */
  1925.         closure.el = el;
  1926.         closure.mkr = posm;
  1927.       }
  1928.  
  1929.     /* Now loop! */
  1930.     for (;;)
  1931.       {
  1932.         EXTENT e;
  1933.         Lisp_Object obj2;
  1934.  
  1935.         /* ----- update position in extent list
  1936.                  and fetch next extent ----- */
  1937.  
  1938.         if (posm)
  1939.           /* fetch POS again to track extent insertions or deletions */
  1940.           pos = extent_list_marker_pos (el, posm);
  1941.         if (pos >= extent_list_num_els (el))
  1942.           break;
  1943.         e = extent_list_at (el, pos, range_endp);
  1944.         pos++;
  1945.         if (posm)
  1946.           /* now point the marker to the next one we're going to process.
  1947.          This ensures graceful behavior if this extent is deleted. */
  1948.           extent_list_move_marker (el, posm, pos);
  1949.  
  1950.         /* ----- deal with internal extents ----- */
  1951.  
  1952.         if (extent_internal_p (e))
  1953.           {
  1954.         if (!(flags & ME_INCLUDE_INTERNAL))
  1955.           continue;
  1956.         else if (e == range)
  1957.           {
  1958.             /* We're processing internal extents and we've
  1959.                come across our own special range extent.
  1960.                (This happens only in adjust_extents*() and
  1961.                process_extents*(), which handle text
  1962.                insertion and deletion.) We need to omit
  1963.                processing of this extent; otherwise
  1964.                we will probably end up prematurely
  1965.                terminating this loop. */
  1966.             continue;
  1967.           }
  1968.           }
  1969.  
  1970.         /* ----- deal with AFTER condition ----- */
  1971.  
  1972.         if (after)
  1973.           {
  1974.         /* if e > after, then we can stop skipping extents. */
  1975.         if (EXTENT_LESS (after, e))
  1976.           after = 0;
  1977.         else /* otherwise, skip this extent. */
  1978.           continue;
  1979.           }
  1980.  
  1981.         /* ----- stop if we're completely outside the range ----- */
  1982.  
  1983.         /* fetch ST and EN again to track text insertions or deletions */
  1984.         if (range)
  1985.           {
  1986.         st = extent_start (range);
  1987.         en = extent_end (range);
  1988.           }
  1989.         if (extent_endpoint (e, range_endp) > en)
  1990.           {
  1991.         /* Can't be mapping over SOE because all extents in
  1992.            there should overlap ST */
  1993.         assert (stage == 1);
  1994.         break;
  1995.           }
  1996.  
  1997.         /* ----- Now actually call the function ----- */
  1998.  
  1999.         obj2 = extent_object (e);
  2000.         if (extent_in_region_p (e,
  2001.                     extent_object_memind_to_bytind (obj2, st),
  2002.                     extent_object_memind_to_bytind (obj2, en),
  2003.                     flags))
  2004.           {
  2005.         if ((*fn)(e, arg))
  2006.           {
  2007.             /* Function wants us to stop mapping. */
  2008.             stage = 1; /* so outer for loop will terminate */
  2009.             break;
  2010.           }
  2011.           }
  2012.       }
  2013.       }
  2014.   /* ---------- Finished looping. ---------- */
  2015.   }
  2016.  
  2017.   if (flags & ME_MIGHT_THROW)
  2018.     /* This deletes the range extent and frees the marker. */
  2019.     unbind_to (count, Qnil);
  2020.   else
  2021.     {
  2022.       /* Delete them ourselves */
  2023.       if (range)
  2024.     extent_detach (range);
  2025.       if (posm)
  2026.     extent_list_delete_marker (el, posm);
  2027.     }
  2028. }
  2029.  
  2030. void
  2031. map_extents (Bufpos from, Bufpos to, emf fn, void *arg,
  2032.          Lisp_Object obj, EXTENT after, unsigned int flags)
  2033. {
  2034.   map_extents_bytind (extent_object_bufpos_to_bytind (obj, from),
  2035.               extent_object_bufpos_to_bytind (obj, to), fn, arg, obj,
  2036.               after, flags);
  2037. }
  2038.  
  2039. /* ------------------------------- */
  2040. /*         adjust_extents()        */
  2041. /* ------------------------------- */
  2042.  
  2043. /* Add AMOUNT to all extent endpoints in the range (FROM, TO].  This
  2044.    happens whenever the gap is moved.  The reason for this is that
  2045.    extent endpoints behave just like markers (all memory indices do)
  2046.    and this adjustment correct for markers -- see adjust_markers().
  2047.    Note that it is important that we visit all extent endpoints in the
  2048.    range, irrespective of whether the endpoints are open or closed.
  2049.  
  2050.    We could use map_extents() for this (and in fact the function
  2051.    was originally written that way), but the gap is in an incoherent
  2052.    state when this function is called and this function plays
  2053.    around with extent endpoints without detaching and reattaching
  2054.    the extents (this is provably correct and saves lots of time),
  2055.    so for safety we make it just look at the extent lists directly.
  2056. */
  2057.  
  2058. void
  2059. adjust_extents (struct buffer *buf, Memind from, Memind to,
  2060.         int amount)
  2061. {
  2062.   int endp;
  2063.   int pos;
  2064.   int startpos[2];
  2065.   Lisp_Object obj = Qnil;
  2066.   Extent_List *el;
  2067.   Stack_Of_Extents *soe;
  2068.  
  2069.   XSETBUFFER (obj, buf);
  2070. #ifdef ERROR_CHECK_EXTENTS
  2071.   sledgehammer_extent_check (obj);
  2072. #endif
  2073.   el = extent_object_extent_list (obj);
  2074.   /* IMPORTANT! Compute the starting positions of the extents to
  2075.      modify BEFORE doing any modification!  Otherwise the starting
  2076.      position for the second time through the loop might get
  2077.      incorrectly calculated (I got bit by this bug real bad). */
  2078.   startpos[0] = extent_list_locate_from_pos (el, from+1, 0);
  2079.   startpos[1] = extent_list_locate_from_pos (el, from+1, 1);
  2080.   for (endp = 0; endp < 2; endp++)
  2081.     {
  2082.       for (pos = startpos[endp]; pos < extent_list_num_els (el);
  2083.        pos++)
  2084.     {
  2085.       EXTENT e = extent_list_at (el, pos, endp);
  2086.       if (extent_endpoint (e, endp) > to)
  2087.         break;
  2088.       set_extent_endpoint (e,
  2089.                    do_marker_adjustment (extent_endpoint (e, endp),
  2090.                              from, to, amount),
  2091.                    endp);
  2092.     }
  2093.     }
  2094.  
  2095.   /* The index for the buffer's SOE is a memory index and thus
  2096.      needs to be adjusted like a marker. */
  2097.   soe = extent_object_stack_of_extents (obj);
  2098.   soe->pos = do_marker_adjustment (soe->pos, from, to, amount);
  2099. }
  2100.  
  2101. /* ------------------------------- */
  2102. /*  adjust_extents_for_deletion()  */
  2103. /* ------------------------------- */
  2104.  
  2105. struct adjust_extents_for_deletion_arg
  2106. {
  2107.   extent_dynarr *list;
  2108. };
  2109.  
  2110. static int
  2111. adjust_extents_for_deletion_mapper (EXTENT extent, void *arg)
  2112. {
  2113.   struct adjust_extents_for_deletion_arg *closure =
  2114.     (struct adjust_extents_for_deletion_arg *) arg;
  2115.  
  2116.   Dynarr_add (closure->list, extent);
  2117.   return 0; /* continue mapping */
  2118. }
  2119.  
  2120. /* For all extent endpoints in the range (FROM, TO], move them to the beginning
  2121.    of the new gap.   Note that it is important that we visit all extent
  2122.    endpoints in the range, irrespective of whether the endpoints are open or
  2123.    closed.
  2124.  */
  2125.  
  2126. void
  2127. adjust_extents_for_deletion (struct buffer *buf, Bytind from,
  2128.                  Bytind to, int gapsize, int numdel)
  2129. {
  2130.   struct adjust_extents_for_deletion_arg closure;
  2131.   int i;
  2132.   Memind oldsoe, newsoe;
  2133.   Lisp_Object bufobj = Qnil;
  2134.  
  2135.   XSETBUFFER (bufobj, buf);
  2136. #ifdef ERROR_CHECK_EXTENTS
  2137.   sledgehammer_extent_check (bufobj);
  2138. #endif
  2139.   closure.list = (extent_dynarr *) Dynarr_new (EXTENT);
  2140.  
  2141.   /* We're going to be playing weird games below with extents and the SOE
  2142.      and such, so compute the list now of all the extents that we're going
  2143.      to muck with.  If we do the mapping and adjusting together, things can
  2144.      get all screwed up. */
  2145.  
  2146.   map_extents_bytind (from, to, adjust_extents_for_deletion_mapper,
  2147.               (void *) &closure, bufobj, 0,
  2148.               /* extent endpoints move like markers regardless
  2149.              of their open/closeness. */
  2150.               ME_ALL_EXTENTS_CLOSED | ME_END_CLOSED |
  2151.               ME_START_OR_END_IN_REGION | ME_INCLUDE_INTERNAL);
  2152.  
  2153.   /*
  2154.     Old and new values for the SOE's position. (It gets adjusted
  2155.     like a marker, just like extent endpoints.)
  2156.   */
  2157.  
  2158.   oldsoe = buf->soe->pos;
  2159.   newsoe = do_marker_adjustment (buf->soe->pos,
  2160.                  (Memind) (to + gapsize),
  2161.                  (Memind) (to + gapsize),
  2162.                  - numdel - gapsize);
  2163.  
  2164.   for (i = 0; i < Dynarr_length (closure.list); i++)
  2165.     {
  2166.       EXTENT extent = Dynarr_at (closure.list, i);
  2167.       Memind new_start, new_end;
  2168.  
  2169.       /* do_marker_adjustment() will not adjust values that should not be
  2170.      adjusted.  We're passing the same funky arguments to
  2171.      do_marker_adjustment() as buffer_delete_range() does. */
  2172.       new_start =
  2173.     do_marker_adjustment (extent_start (extent),
  2174.                   (Memind) (to + gapsize),
  2175.                   (Memind) (to + gapsize),
  2176.                   - numdel - gapsize);
  2177.       new_end =
  2178.     do_marker_adjustment (extent_end (extent),
  2179.                   (Memind) (to + gapsize),
  2180.                   (Memind) (to + gapsize),
  2181.                   - numdel - gapsize);
  2182.  
  2183.       /* We need to be very careful here so that the SOE doesn't get
  2184.      corrupted.  We are shrinking extents out of the deleted region
  2185.      and simultaneously moving the SOE's pos out of the deleted
  2186.      region, so the SOE should contain the same extents at the end
  2187.      as at the beginning.  However, extents may get reordered
  2188.      by this process, so we have to operate by pulling the extents
  2189.      out of the buffer and SOE, changing their bounds, and then
  2190.      reinserting them.  In order for the SOE not to get screwed up,
  2191.      we have to make sure that the SOE's pos points to its old
  2192.      location whenever we pull an extent out, and points to its
  2193.      new location whenever we put the extent back in.
  2194.        */
  2195.  
  2196.       if (new_start != extent_start (extent) ||
  2197.       new_end != extent_end (extent))
  2198.     {
  2199.       extent_detach (extent);
  2200.       set_extent_start (extent, new_start);
  2201.       set_extent_end (extent, new_end);
  2202.       buf->soe->pos = newsoe;
  2203.       extent_attach (extent);
  2204.       buf->soe->pos = oldsoe;
  2205.     }
  2206.     }
  2207.       
  2208.   buf->soe->pos = newsoe;
  2209.  
  2210. #ifdef ERROR_CHECK_EXTENTS
  2211.   sledgehammer_extent_check (bufobj);
  2212. #endif
  2213.   Dynarr_free (closure.list);
  2214. }
  2215.  
  2216. /* ------------------------------- */
  2217. /*         extent fragments        */
  2218. /* ------------------------------- */
  2219.  
  2220. /* Imagine that the buffer is divided up into contiguous,
  2221.    nonoverlapping "runs" of text such that no extent
  2222.    starts or ends within a run (extents that abut the
  2223.    run don't count).  This function returns the position
  2224.    of the beginning of the first run that begins after POS,
  2225.    or returns POS if there are no such runs. */
  2226.  
  2227. static Bytind
  2228. extent_find_end_of_run (Lisp_Object obj, Bytind pos, int outside_accessible)
  2229. {
  2230.   Extent_List *sel = extent_object_stack_of_extents (obj)->extents;
  2231.   Extent_List *bel = extent_object_extent_list (obj);
  2232.   Bytind pos1, pos2;
  2233.   int elind1, elind2;
  2234.   Memind mempos = extent_object_bytind_to_memind (obj, pos);
  2235.   Bytind limit = outside_accessible ?
  2236.     extent_object_absolute_limit (obj) :
  2237.       extent_object_accessible_limit (obj);
  2238.  
  2239.   soe_move (obj, mempos);
  2240.  
  2241.   /* Find the first start position after POS. */
  2242.   elind1 = extent_list_locate_from_pos (bel, mempos+1, 0);
  2243.   if (elind1 < extent_list_num_els (bel))
  2244.     pos1 = extent_object_memind_to_bytind
  2245.       (obj, extent_start (extent_list_at (bel, elind1, 0)));
  2246.   else
  2247.     pos1 = limit;
  2248.  
  2249.   /* Find the first end position after POS.  The extent corresponding
  2250.      to this position is either in the SOE or is greater than or
  2251.      equal to POS1, so we just have to look in the SOE. */
  2252.   elind2 = extent_list_locate_from_pos (sel, mempos+1, 1);
  2253.   if (elind2 < extent_list_num_els (sel))
  2254.     pos2 = extent_object_memind_to_bytind
  2255.       (obj, extent_end (extent_list_at (sel, elind2, 1)));
  2256.   else
  2257.     pos2 = limit;
  2258.  
  2259.   return min (min (pos1, pos2), limit);
  2260. }
  2261.  
  2262. static Bytind
  2263. extent_find_beginning_of_run (Lisp_Object obj, Bytind pos,
  2264.                   int outside_accessible)
  2265. {
  2266.   Extent_List *sel = extent_object_stack_of_extents (obj)->extents;
  2267.   Extent_List *bel = extent_object_extent_list (obj);
  2268.   Bytind pos1, pos2;
  2269.   int elind1, elind2;
  2270.   Memind mempos = extent_object_bytind_to_memind (obj, pos);
  2271.   Bytind limit = outside_accessible ?
  2272.     extent_object_absolute_start (obj) :
  2273.       extent_object_accessible_start (obj);
  2274.  
  2275.   soe_move (obj, mempos);
  2276.  
  2277.   /* Find the first end position before POS. */
  2278.   elind1 = extent_list_locate_from_pos (bel, mempos, 1);
  2279.   if (elind1 > 0)
  2280.     pos1 = extent_object_memind_to_bytind
  2281.       (obj,
  2282.        extent_end (extent_list_at (bel, elind1 - 1, 1)));
  2283.   else
  2284.     pos1 = limit;
  2285.  
  2286.   /* Find the first start position before POS.  The extent corresponding
  2287.      to this position is either in the SOE or is less than or
  2288.      equal to POS1, so we just have to look in the SOE. */
  2289.   elind2 = extent_list_locate_from_pos (sel, mempos, 0);
  2290.   if (elind2 > 0)
  2291.     pos2 = extent_object_memind_to_bytind
  2292.       (obj, extent_start (extent_list_at (sel, elind2 - 1, 0)));
  2293.   else
  2294.     pos2 = limit;
  2295.  
  2296.   return max (max (pos1, pos2), limit);
  2297. }
  2298.  
  2299. struct extent_fragment *
  2300. extent_fragment_new (struct buffer *buf, struct frame *frm)
  2301. {
  2302.   struct extent_fragment *ef = (struct extent_fragment *)
  2303.     xmalloc (sizeof (struct extent_fragment));
  2304.  
  2305.   memset (ef, 0, sizeof (*ef));
  2306.   ef->buf = buf;
  2307.   ef->frm = frm;
  2308.   ef->extents = Dynarr_new (EXTENT);
  2309.   ef->begin_glyphs = Dynarr_new (struct glyph_block);
  2310.   ef->end_glyphs = Dynarr_new (struct glyph_block);
  2311.  
  2312.   return ef;
  2313. }
  2314.  
  2315. void
  2316. extent_fragment_delete (struct extent_fragment *ef)
  2317. {
  2318.   Dynarr_free (ef->extents);
  2319.   Dynarr_free (ef->begin_glyphs);
  2320.   Dynarr_free (ef->end_glyphs);
  2321.   xfree (ef);
  2322. }
  2323.  
  2324. static int
  2325. extent_priority_sort_function (const void *humpty, const void *dumpty)
  2326. {
  2327.   EXTENT foo = * (EXTENT *) humpty;
  2328.   EXTENT bar = * (EXTENT *) dumpty;
  2329.   if (extent_priority (foo) < extent_priority (bar))
  2330.     return -1;
  2331.   return (extent_priority (foo) > extent_priority (bar));
  2332. }
  2333.  
  2334. static void
  2335. extent_fragment_sort_by_priority (extent_dynarr *extarr)
  2336. {
  2337.   int i;
  2338.  
  2339.   /* Sort our copy of the stack by extent_priority.  We use a bubble
  2340.      sort here because it's going to be faster than qsort() for small
  2341.      numbers of extents (less than 10 or so), and 99.999% of the time
  2342.      there won't ever be more extents than this in the stack. */
  2343.   if (Dynarr_length (extarr) < 10)
  2344.     {
  2345.       for (i = 1; i < Dynarr_length (extarr); i++)
  2346.     {
  2347.       int j = i - 1;
  2348.       while (j >= 0 &&
  2349.          (extent_priority (Dynarr_at (extarr, j)) >
  2350.           extent_priority (Dynarr_at (extarr, j+1))))
  2351.         {
  2352.           EXTENT tmp = Dynarr_at (extarr, j);
  2353.           Dynarr_at (extarr, j) = Dynarr_at (extarr, j+1);
  2354.           Dynarr_at (extarr, j+1) = tmp;
  2355.           j--;
  2356.         }
  2357.     }
  2358.     }
  2359.   else
  2360.     /* But some loser programs mess up and may create a large number
  2361.        of extents overlapping the same spot.  This will result in
  2362.        catastrophic behavior if we use the bubble sort above. */
  2363.     qsort (Dynarr_atp (extarr, 0), Dynarr_length (extarr),
  2364.        sizeof (EXTENT), extent_priority_sort_function);
  2365. }
  2366.  
  2367. face_index
  2368. extent_fragment_update (struct window *w, struct extent_fragment *ef,
  2369.             Bytind pos)
  2370. {
  2371.   int i;
  2372.   Extent_List *sel = ef->buf->soe->extents;
  2373.   EXTENT lhe = 0;
  2374.   struct extent dummy_lhe_extent;
  2375.   Memind mempos = bytind_to_memind (ef->buf, pos);
  2376.  
  2377.   assert (pos >= BI_BUF_BEGV (ef->buf) && pos <= BI_BUF_ZV (ef->buf));
  2378.  
  2379.   Dynarr_reset (ef->extents);
  2380.   Dynarr_reset (ef->begin_glyphs);
  2381.   Dynarr_reset (ef->end_glyphs);
  2382.   ef->invisible = 0;
  2383.  
  2384.   /* Set up the begin and end positions. */
  2385.   ef->pos = pos;
  2386.   ef->end = extent_find_end_of_run (make_buffer (ef->buf), pos, 0);
  2387.  
  2388.   /* Note that extent_find_end_of_run() already moved the SOE for us. */
  2389.   /* soe_move (ef->buf, mempos); */
  2390.  
  2391.   /* Determine the begin glyphs at POS. */
  2392.   for (i = 0; i < extent_list_num_els (sel); i++)
  2393.     {
  2394.       EXTENT e = extent_list_at (sel, i, 0);
  2395.       if (extent_start (e) == mempos && !NILP (extent_begin_glyph (e)))
  2396.     {
  2397.       Lisp_Object glyph = extent_begin_glyph (e);
  2398.       struct glyph_block gb;
  2399.       
  2400.       gb.glyph = glyph;
  2401.       gb.extent = Qnil;
  2402.       XSETEXTENT (gb.extent, e);
  2403.       Dynarr_add (ef->begin_glyphs, gb);
  2404.     }
  2405.     }
  2406.   
  2407.   /* Determine the end glyphs at POS. */
  2408.   for (i = 0; i < extent_list_num_els (sel); i++)
  2409.     {
  2410.       EXTENT e = extent_list_at (sel, i, 1);
  2411.       if (extent_end (e) == mempos && !NILP (extent_end_glyph (e)))
  2412.     {
  2413.       Lisp_Object glyph = extent_end_glyph (e);
  2414.       struct glyph_block gb;
  2415.       
  2416.       gb.glyph = glyph;
  2417.       gb.extent = Qnil;
  2418.       XSETEXTENT (gb.extent, e);
  2419.       Dynarr_add (ef->end_glyphs, gb);
  2420.     }
  2421.     }
  2422.  
  2423.   /* Determine whether the last-highlighted-extent is present. */
  2424.   if (EXTENTP (Vlast_highlighted_extent))
  2425.     lhe = XEXTENT (Vlast_highlighted_extent);
  2426.  
  2427.   /* Now add all extents that overlap the character after POS and
  2428.      have a non-nil face.  Also check if the character is invisible. */
  2429.   for (i = 0; i < extent_list_num_els (sel); i++)
  2430.     {
  2431.       EXTENT e = extent_list_at (sel, i, 0);
  2432.       if (extent_end (e) > mempos)
  2433.     {
  2434.       if (extent_invisible_p (e))
  2435.         ef->invisible = 1;
  2436.       if (!NILP (extent_face (e)) || e == lhe)
  2437.         {
  2438.           Dynarr_add (ef->extents, e);
  2439.           if (e == lhe)
  2440.         {
  2441.           /* memset isn't really necessary; we only deref `priority' */
  2442.           memset (&dummy_lhe_extent, 0, sizeof (dummy_lhe_extent));
  2443.           set_extent_priority (&dummy_lhe_extent,
  2444.                        mouse_highlight_priority);
  2445.           Dynarr_add (ef->extents, &dummy_lhe_extent);
  2446.         }
  2447.         }
  2448.     }
  2449.     }
  2450.  
  2451.   extent_fragment_sort_by_priority (ef->extents);
  2452.  
  2453.   /* Now merge the faces together into a single face.  The code to
  2454.      do this is in faces.c because it involves manipulating faces. */
  2455.   return get_extent_fragment_face_cache_index (w, ef, &dummy_lhe_extent);
  2456. }      
  2457.  
  2458.  
  2459. /************************************************************************/
  2460. /*                  extent-object methods                */
  2461. /************************************************************************/
  2462.  
  2463. /* These are the basic helper functions for handling the allocation of
  2464.    extent objects and extent-replica objects.  They are similar to
  2465.    the functions for other lrecord objects.  make_extent() is in
  2466.    alloc.c, not here. */
  2467.  
  2468. static Lisp_Object mark_extent (Lisp_Object, void (*) (Lisp_Object));
  2469. static Lisp_Object mark_extent_replica (Lisp_Object, void (*) (Lisp_Object));
  2470. static int extent_equal (Lisp_Object, Lisp_Object, int depth);
  2471. static int extent_replica_equal (Lisp_Object, Lisp_Object, int depth);
  2472. static unsigned long extent_hash (Lisp_Object obj, int depth);
  2473. static unsigned long extent_replica_hash (Lisp_Object obj, int depth);
  2474. static void print_extent_or_replica (Lisp_Object obj,
  2475.                      Lisp_Object printcharfun, int escapeflag);
  2476. static int extent_getprop (Lisp_Object obj, Lisp_Object prop,
  2477.                Lisp_Object *value_out);
  2478. static int extent_putprop (Lisp_Object obj, Lisp_Object prop,
  2479.                Lisp_Object value);
  2480. static int extent_remprop (Lisp_Object obj, Lisp_Object prop);
  2481. static Lisp_Object extent_props (Lisp_Object obj);
  2482.  
  2483. DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS ("extent", extent,
  2484.                       mark_extent,
  2485.                       print_extent_or_replica, 0,
  2486.                       extent_equal, extent_hash,
  2487.                       extent_getprop, extent_putprop,
  2488.                       extent_remprop, extent_props,
  2489.                       struct extent);
  2490. DEFINE_LRECORD_IMPLEMENTATION ("extent-replica", extent_replica,
  2491.                                mark_extent_replica, print_extent_or_replica,
  2492.                                0, extent_replica_equal, extent_replica_hash,
  2493.                    struct extent_replica);
  2494.  
  2495.  
  2496. static Lisp_Object
  2497. mark_extent (Lisp_Object obj, void (*markobj) (Lisp_Object))
  2498. {
  2499.   struct extent *extent = XEXTENT (obj);
  2500.   if (gc_record_type_p (extent_object (extent), lrecord_extent))
  2501.     /* Can't be a replica here! */
  2502.     abort ();
  2503.  
  2504.   ((markobj) (extent_object (extent)));
  2505.   ((markobj) (extent_face (extent)));
  2506.   return (extent->plist);
  2507. }
  2508.  
  2509. /* Extents in a buffer are not threaded like normal Lisp_Objects, but
  2510.    are stored in an array.  Furthermore, the direct pointers are used
  2511.    rather than the Lisp_Objects. (This would fail if we had a
  2512.    relocating garbage collector, but that is not likely to ever
  2513.    happen.) So we have to loop over them ourselves.  This function
  2514.    is called from mark_buffer(). */
  2515.  
  2516. void
  2517. mark_buffer_extents (struct buffer *buf, void (*markobj) (Lisp_Object))
  2518. {
  2519.   int i;
  2520.   Extent_List *list = buf->extents;
  2521.  
  2522.   /* Vbuffer_defaults and Vbuffer_local_symbols are buffer-like
  2523.      objects that are created specially and never have their extent
  2524.      list initialized (or rather, it is set to zero in
  2525.      nuke_all_buffer_slots()).  However, these objects get
  2526.      garbage-collected so we have to deal.
  2527.  
  2528.      (Also the list can be zero when we're dealing with a destroyed
  2529.      buffer.) */
  2530.  
  2531.   if (!list)
  2532.     return;
  2533.  
  2534.   for (i = 0; i < extent_list_num_els (list); i++)
  2535.     {
  2536.       struct extent *extent = extent_list_at (list, i, 0);
  2537.       Lisp_Object obj = Qnil;
  2538.  
  2539.       XSETEXTENT (obj, extent);
  2540.       ((markobj) (obj));
  2541.       ((markobj) (extent->plist));
  2542.       ((markobj) (extent_object (extent)));
  2543.     }
  2544. }
  2545.  
  2546. static Lisp_Object
  2547. mark_extent_replica (Lisp_Object obj, void (*markobj) (Lisp_Object))
  2548. {
  2549.   struct extent_replica *dup = XEXTENT_REPLICA (obj);
  2550.   if (!gc_record_type_p (extent_replica_extent (dup), lrecord_extent))
  2551.     /* Can't be an extent here! */
  2552.     abort ();
  2553.   return (extent_replica_extent (dup));
  2554. }
  2555.  
  2556. static char *
  2557. print_extent_1 (char *buf, Lisp_Object extent_obj)
  2558. {
  2559.   Bufpos from = XINT (Fextent_start_position (extent_obj));
  2560.   Bufpos to = XINT (Fextent_end_position (extent_obj));
  2561.   EXTENT ext = XEXTENT (extent_obj);
  2562.   EXTENT anc = extent_ancestor (ext);
  2563.   char *bp = buf;
  2564.   Lisp_Object tail;
  2565.  
  2566.   /* Retrieve the ancestor and use it, for faster retrieval of properties */
  2567.  
  2568.   if (!NILP (extent_begin_glyph (anc))) *bp++ = '*';
  2569.   *bp++ = (extent_start_open_p (anc) ? '(': '[');
  2570.   if (extent_detached_p (ext))
  2571.     sprintf (bp, "detached");
  2572.   else
  2573.     sprintf (bp, "%d, %d", from, to);
  2574.   bp += strlen (bp);
  2575.   *bp++ = (extent_end_open_p (anc) ? ')': ']');
  2576.   if (!NILP (extent_end_glyph (anc))) *bp++ = '*';
  2577.   *bp++ = ' ';
  2578.  
  2579.   if (extent_read_only_p (anc)) *bp++ = '%';
  2580.   if (extent_highlight_p (anc)) *bp++ = 'H';
  2581.   if (extent_unique_p (anc)) *bp++ = 'U';
  2582.   else if (extent_duplicable_p (anc)) *bp++ = 'D';
  2583.   if (extent_invisible_p (anc)) *bp++ = 'I';
  2584.  
  2585.   if (extent_read_only_p (anc) || extent_highlight_p (anc) ||
  2586.       extent_unique_p (anc) || extent_duplicable_p (anc) ||
  2587.       extent_invisible_p (anc))
  2588.     *bp++ = ' ';
  2589.  
  2590.   tail = extent_plist (anc);
  2591.  
  2592.   for (; !NILP (tail); tail = Fcdr (Fcdr (tail)))
  2593.     {
  2594.       struct Lisp_String *k = XSYMBOL (XCAR (tail))->name;
  2595.       Lisp_Object v = XCAR (XCDR (tail));
  2596.       if (NILP (v)) continue;
  2597.       memcpy (bp, (char *) string_data (k), string_length (k));
  2598.       bp += string_length (k);
  2599.       *bp++ = ' ';
  2600.     }
  2601.  
  2602.   sprintf (bp, "0x%lx", (long) ext);
  2603.   bp += strlen (bp);
  2604.  
  2605.   *bp++ = 0;
  2606.   return buf;
  2607. }
  2608.  
  2609. static char *
  2610. print_extent_replica_1 (char *buf, Lisp_Object extent_replica)
  2611. {
  2612.   char buf2[256];
  2613.  
  2614.   Lisp_Object extent =
  2615.     extent_replica_extent (XEXTENT_REPLICA (extent_replica));
  2616.   if (EXTENT_LIVE_P (XEXTENT (extent)))
  2617.     sprintf (buf, "[%d, %d) of extent %s",
  2618.          extent_replica_start (XEXTENT_REPLICA (extent_replica)),
  2619.          extent_replica_end (XEXTENT_REPLICA (extent_replica)),
  2620.          print_extent_1 (buf2, extent));
  2621.   else
  2622.     sprintf (buf, "[%d, %d) of destroyed extent",
  2623.          extent_replica_start (XEXTENT_REPLICA (extent_replica)),
  2624.          extent_replica_end (XEXTENT_REPLICA (extent_replica)));
  2625.   return buf;
  2626. }
  2627.  
  2628. static void
  2629. print_extent_or_replica (Lisp_Object obj, 
  2630.                          Lisp_Object printcharfun, int escapeflag)
  2631. {
  2632.   char buf2[256];
  2633.  
  2634.   if (EXTENTP (obj))
  2635.     {
  2636.       if (escapeflag)
  2637.     {
  2638.       CONST char *title = "";
  2639.       CONST char *name = "";
  2640.       Lisp_Object obj2 = Qnil;
  2641.       char stringname[30];
  2642.       
  2643.       /* Destroyed extents have 't' in the object field, causing
  2644.          extent_object() to abort (maybe). */
  2645.       if (EXTENT_LIVE_P (XEXTENT (obj)))
  2646.         obj2 = extent_object (XEXTENT (obj));
  2647.  
  2648.       if (NILP (obj2))
  2649.         title = "no buffer";
  2650.       else if (BUFFERP (obj2))
  2651.         {
  2652.           if (BUFFER_LIVE_P (XBUFFER (obj2)))
  2653.         {
  2654.           title = "buffer ";
  2655.           name = (char *) string_data (XSTRING (XBUFFER (obj2)->name));
  2656.         }
  2657.           else
  2658.         {
  2659.           title = "Killed Buffer";
  2660.           name = "";
  2661.         }
  2662.         }
  2663.       else
  2664.         {
  2665.           assert (STRINGP (obj2));
  2666.           title = "string ";
  2667.           sprintf (stringname, "0x%x", (unsigned int) XSTRING (obj2));
  2668.         }
  2669.       
  2670.       if (print_readably)
  2671.         {
  2672.           if (!EXTENT_LIVE_P (XEXTENT (obj)))
  2673.         error ("printing unreadable object #<destroyed extent>");
  2674.           else
  2675.         error ("printing unreadable object #<extent %s>",
  2676.                print_extent_1 (buf2, obj));
  2677.         }
  2678.       
  2679.       if (!EXTENT_LIVE_P (XEXTENT (obj)))
  2680.         write_c_string ("#<destroyed extent", printcharfun);
  2681.       else
  2682.         {
  2683.           char buf[256];
  2684.           write_c_string ("#<extent ", printcharfun);
  2685.           if (extent_detached_p (XEXTENT (obj)))
  2686.         sprintf (buf, "%s from %s%s",
  2687.              print_extent_1 (buf2, obj), title, name);
  2688.           else
  2689.         sprintf (buf, "%s in %s%s",
  2690.              print_extent_1 (buf2, obj),
  2691.              title, name);
  2692.           write_c_string (buf, printcharfun);
  2693.         }
  2694.     }
  2695.       else
  2696.     {
  2697.       if (print_readably)
  2698.         error ("printing unreadable object #<extent>");
  2699.       write_c_string ("#<extent", printcharfun);
  2700.     }
  2701.       write_c_string (">", printcharfun);
  2702.     }
  2703.   else if (EXTENT_REPLICAP (obj))
  2704.     {
  2705.       if (escapeflag)
  2706.     {
  2707.       if (print_readably)
  2708.         {
  2709.           if (!EXTENT_REPLICA_LIVE_P (XEXTENT_REPLICA (obj)))
  2710.         error
  2711.           ("printing unreadable object #<destroyed extent-replica>");
  2712.           else
  2713.         error ("printing unreadable object #<extent-replica %s>",
  2714.                print_extent_replica_1 (buf2, obj));
  2715.         }
  2716.  
  2717.       if (!EXTENT_REPLICA_LIVE_P (XEXTENT_REPLICA (obj)))
  2718.         write_c_string ("#<destroyed extent-replica", printcharfun);
  2719.       else
  2720.         {
  2721.           write_c_string ("#<extent-replica ", printcharfun);
  2722.           print_extent_replica_1 (buf2, obj);
  2723.           write_c_string (buf2, printcharfun);
  2724.         }
  2725.     }
  2726.       else
  2727.     {
  2728.       if (print_readably)
  2729.         error ("printing unreadable object #<extent-replica>");
  2730.       write_c_string ("#<extent-replica", printcharfun);
  2731.     }
  2732.       write_c_string (">", printcharfun);
  2733.     }
  2734. }
  2735.  
  2736. static int
  2737. properties_equal (EXTENT e1, EXTENT e2, int depth)
  2738. {
  2739.   /* When this function is called, all indirections have been followed.
  2740.      Thus, the indirection checks in the various macros below will not
  2741.      amount to anything, and could be removed.  However, the time
  2742.      savings would probably not be significant. */
  2743.   if (!(EQ (extent_face (e1), extent_face (e2)) &&
  2744.     extent_priority (e1) == extent_priority (e2) &&
  2745.     internal_equal (extent_begin_glyph (e1), extent_begin_glyph (e2),
  2746.             depth + 1) &&
  2747.     internal_equal (extent_end_glyph (e1), extent_end_glyph (e2),
  2748.             depth + 1)))
  2749.     return 0;
  2750.  
  2751.   /* compare the bit flags. */
  2752.   {
  2753.     /* The has_aux field should not be relevant. */
  2754.     int e1_has_aux = e1->flags.has_aux;
  2755.     int e2_has_aux = e2->flags.has_aux;
  2756.     int value;
  2757.  
  2758.     e1->flags.has_aux = e2->flags.has_aux = 0;
  2759.     value = memcmp (&e1->flags, &e2->flags, sizeof (e1->flags));
  2760.     e1->flags.has_aux = e1_has_aux;
  2761.     e2->flags.has_aux = e2_has_aux;
  2762.     if (value)
  2763.       return 0;
  2764.   }
  2765.  
  2766.   /* compare the random elements of the plists. */
  2767.   return (!plists_differ (extent_ancestor_plist (e1),
  2768.               extent_ancestor_plist (e2),
  2769.               depth + 1));
  2770. }
  2771.  
  2772. static int
  2773. extent_equal (Lisp_Object o1, Lisp_Object o2, int depth)
  2774. {
  2775.   struct extent *e1 = XEXTENT (o1);
  2776.   struct extent *e2 = XEXTENT (o2);
  2777.   return
  2778.     (extent_start (e1) == extent_start (e2) &&
  2779.      extent_end (e1) == extent_end (e2) &&
  2780.      internal_equal (extent_object (e1), extent_object (e2), depth + 1) &&
  2781.      properties_equal (extent_ancestor (e1), extent_ancestor (e2),
  2782.                depth));
  2783. }
  2784.  
  2785. static int
  2786. extent_replica_equal (Lisp_Object o1, Lisp_Object o2, int depth)
  2787. {
  2788.   struct extent_replica *e1 = XEXTENT_REPLICA (o1);
  2789.   struct extent_replica *e2 = XEXTENT_REPLICA (o2);
  2790.   if (!EXTENT_REPLICA_LIVE_P (e1) && !EXTENT_REPLICA_LIVE_P (e2))
  2791.     return 1;
  2792.   return (extent_replica_start (e1) == extent_replica_start (e2) &&
  2793.       extent_replica_end (e1) == extent_replica_end (e2) &&
  2794.       internal_equal (extent_replica_extent (e1),
  2795.               extent_replica_extent (e2), depth + 1));
  2796. }
  2797.  
  2798. static unsigned long
  2799. extent_hash (Lisp_Object obj, int depth)
  2800. {
  2801.   struct extent *e = XEXTENT (obj);
  2802.   /* No need to hash all of the elements; that would take too long.
  2803.      Just hash the most common ones. */
  2804.   return HASH3 (extent_start (e), extent_end (e),
  2805.         internal_hash (extent_object (e), depth + 1));
  2806. }
  2807.  
  2808. static unsigned long
  2809. extent_replica_hash (Lisp_Object obj, int depth)
  2810. {
  2811.   struct extent_replica *e = XEXTENT_REPLICA (obj);
  2812.   if (!EXTENT_REPLICA_LIVE_P (e))
  2813.     return 0;
  2814.   return HASH3 (extent_replica_start (e), extent_replica_end (e),
  2815.         internal_hash (extent_replica_extent (e), depth + 1));
  2816. }
  2817.  
  2818. static int
  2819. extent_getprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object *value_out)
  2820. {
  2821.   error ("Not yet implemented"); /* #### */
  2822.   return 0;
  2823. }
  2824.  
  2825. static int
  2826. extent_putprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
  2827. {
  2828.   error ("Not yet implemented"); /* #### */
  2829.   return 0;
  2830. }
  2831.  
  2832. static int
  2833. extent_remprop (Lisp_Object obj, Lisp_Object prop)
  2834. {
  2835.   error ("Not yet implemented"); /* #### */
  2836.   return 0;
  2837. }
  2838.  
  2839. static Lisp_Object
  2840. extent_props (Lisp_Object obj)
  2841. {
  2842.   error ("Not yet implemented"); /* #### */
  2843.   return Qnil;
  2844. }
  2845.  
  2846.  
  2847. /************************************************************************/
  2848. /*            basic extent accessors                */
  2849. /************************************************************************/
  2850.  
  2851. /* These functions are for checking externally-passed extent objects
  2852.    and returning an extent's basic properties, which include the
  2853.    buffer the extent is associated with, the endpoints of the extent's
  2854.    range, the open/closed-ness of those endpoints, and whether the
  2855.    extent is detached.  Manipulating these properties requires
  2856.    manipulating the ordered lists that hold extents; thus, functions
  2857.    to do that are in a later section. */
  2858.  
  2859. /* Given a Lisp_Object that is supposed to be an extent, make sure it
  2860.    is OK and return an extent pointer.  Extents can be in one of four
  2861.    states:
  2862.  
  2863.    1) destroyed
  2864.    2) detached and not associated with a buffer
  2865.    3) detached and associated with a buffer
  2866.    4) attached to a buffer
  2867.  
  2868.    If FLAGS is 0, types 2-4 are allowed.  If FLAGS is DE_MUST_HAVE_BUFFER,
  2869.    types 3-4 are allowed.  If FLAGS is DE_MUST_BE_ATTACHED, only type 4
  2870.    is allowed.
  2871.    */
  2872.  
  2873. static EXTENT
  2874. decode_extent (Lisp_Object extent_obj, unsigned int flags)
  2875. {
  2876.   EXTENT extent;
  2877.   Lisp_Object obj;
  2878.  
  2879.   CHECK_LIVE_EXTENT (extent_obj, 0);
  2880.   extent = XEXTENT (extent_obj);
  2881.   obj = extent_object (extent);
  2882.  
  2883.   /* the following condition will fail if we're dealing with a freed extent
  2884.      or an extent replica */
  2885.   assert (NILP (obj) || BUFFERP (obj) || STRINGP (obj));
  2886.  
  2887.   if (flags & DE_MUST_BE_ATTACHED)
  2888.     flags |= DE_MUST_HAVE_BUFFER;
  2889.  
  2890.   /* if buffer is dead, then convert extent to have no buffer. */
  2891.   if (BUFFERP (obj) && !BUFFER_LIVE_P (XBUFFER (obj)))
  2892.     obj = extent_object (extent) = Qnil;
  2893.  
  2894.   assert (!NILP (obj) || extent_detached_p (extent));
  2895.  
  2896.   if (NILP (obj) && (flags & DE_MUST_HAVE_BUFFER))
  2897.     {
  2898.       Lisp_Object extent_obj;
  2899.       XSETEXTENT (extent_obj, extent);
  2900.       signal_simple_error ("extent doesn't belong to a buffer",
  2901.                extent_obj);
  2902.     }
  2903.   
  2904.   if (extent_detached_p (extent) && (flags & DE_MUST_BE_ATTACHED))
  2905.     {
  2906.       Lisp_Object extent_obj;
  2907.       XSETEXTENT (extent_obj, extent);
  2908.       signal_simple_error ("extent cannot be detached", extent_obj);
  2909.     }
  2910.  
  2911.   return extent;
  2912. }
  2913.  
  2914. /* Note that the returned value is a buffer position, not a byte index. */
  2915.  
  2916. static Lisp_Object
  2917. extent_endpoint_external (Lisp_Object extent_obj, int endp)
  2918. {
  2919.   EXTENT extent = decode_extent (extent_obj, 0);
  2920.  
  2921.   if (extent_detached_p (extent))
  2922.     return Qnil;
  2923.   else
  2924.     return make_number (extent_endpoint_bufpos (extent, endp));
  2925. }
  2926.  
  2927. DEFUN ("extentp", Fextentp, Sextentp, 1, 1, 0,
  2928.   "T if OBJECT is an extent.")
  2929.   (object)
  2930.      Lisp_Object object;
  2931. {
  2932.   if (EXTENTP (object))
  2933.     return Qt;
  2934.   return Qnil;
  2935. }
  2936.  
  2937. DEFUN ("extent-live-p", Fextent_live_p, Sextent_live_p, 1, 1, 0,
  2938.   "T if OBJECT is an extent and the extent has not been destroyed.")
  2939.   (object)
  2940.      Lisp_Object object;
  2941. {
  2942.   if (EXTENTP (object) && EXTENT_LIVE_P (XEXTENT (object)))
  2943.     return Qt;
  2944.   return Qnil;
  2945. }
  2946.  
  2947. DEFUN ("extent-detached-p", Fextent_detached_p, Sextent_detached_p, 1, 1, 0,
  2948.   "T if EXTENT is detached.")
  2949.   (extent)
  2950.      Lisp_Object extent;
  2951. {
  2952.   if (extent_detached_p (decode_extent (extent, 0)))
  2953.     return Qt;
  2954.   return Qnil;
  2955. }
  2956.  
  2957. /* #### This will soon get renamed to `extent-object', with
  2958.    extent-buffer being an obsolete alias for it. */
  2959. DEFUN ("extent-buffer", Fextent_object, Sextent_object, 1, 1, 0,
  2960.        "Return buffer of EXTENT.")
  2961.      (extent)
  2962.      Lisp_Object extent;
  2963. {
  2964.   return extent_object (decode_extent (extent, 0));
  2965. }
  2966.  
  2967. DEFUN ("extent-start-position", Fextent_start_position, 
  2968.        Sextent_start_position, 1, 1, 0,
  2969.        "Return start position of EXTENT, or nil if EXTENT is detached.")
  2970.      (extent)
  2971.      Lisp_Object extent;
  2972. {
  2973.   return extent_endpoint_external (extent, 0);
  2974. }
  2975.  
  2976. DEFUN ("extent-end-position", Fextent_end_position, 
  2977.        Sextent_end_position, 1, 1, 0,
  2978.        "Return end position of EXTENT, or nil if EXTENT is detached.")
  2979.      (extent)
  2980.      Lisp_Object extent;
  2981. {
  2982.   return extent_endpoint_external (extent, 1);
  2983. }
  2984.  
  2985. DEFUN ("extent-length", Fextent_length, Sextent_length, 1, 1, 0,
  2986.        "Return length of EXTENT in characters.")
  2987.      (extent)
  2988.      Lisp_Object extent;
  2989. {
  2990.   EXTENT e = decode_extent (extent, DE_MUST_BE_ATTACHED);
  2991.   return
  2992.     make_number (extent_endpoint_bufpos (e, 1) -
  2993.          extent_endpoint_bufpos (e, 0));
  2994. }
  2995.  
  2996. DEFUN ("next-extent", Fnext_extent, Snext_extent, 1, 1, 0,
  2997.        "Find next extent after EXTENT.\n\
  2998. If EXTENT is a buffer return the first extent in the buffer.\n\
  2999. Extents in a buffer are ordered in what is called the \"display\"\n\
  3000.  order, which sorts by increasing start positions and then by *decreasing*\n\
  3001.  end positions.\n\
  3002. If you want to perform an operation on a series of extents, use\n\
  3003.  `map-extents' instead of this function; it is much more efficient.\n\
  3004.  The primary use of this function should be to enumerate all the\n\
  3005.  extents in a buffer.\n\
  3006. Note: The display order is not necessarily the order that `map-extents'\n\
  3007.  processes extents in!")
  3008.   (extent)
  3009.    Lisp_Object extent;
  3010. {
  3011.   Lisp_Object val;
  3012.   EXTENT next;
  3013.  
  3014.   if (EXTENTP (extent))
  3015.     next = extent_next (decode_extent (extent, DE_MUST_BE_ATTACHED));
  3016.   else
  3017.     next = extent_first (decode_extent_object (extent));
  3018.  
  3019.   if (!next)
  3020.     return (Qnil);
  3021.   XSETEXTENT (val, next);
  3022.   return (val);
  3023. }
  3024.  
  3025. DEFUN ("previous-extent", Fprevious_extent, Sprevious_extent, 1, 1, 0,
  3026.        "Find last extent before EXTENT.\n\
  3027. If EXTENT is a buffer return the last extent in the buffer.\n\
  3028. This function is analogous to `next-extent'.")
  3029.   (extent)
  3030.    Lisp_Object extent;
  3031. {
  3032.   Lisp_Object val;
  3033.   EXTENT prev;
  3034.  
  3035.   if (EXTENTP (extent))
  3036.     prev = extent_previous (decode_extent (extent, DE_MUST_BE_ATTACHED));
  3037.   else
  3038.     prev = extent_last (decode_extent_object (extent));
  3039.  
  3040.   if (!prev)
  3041.     return (Qnil);
  3042.   XSETEXTENT (val, prev);
  3043.   return (val);
  3044. }
  3045.  
  3046. #ifdef DEBUG_XEMACS
  3047.  
  3048. DEFUN ("next-e-extent", Fnext_e_extent, Snext_e_extent, 1, 1, 0,
  3049.        "Find next extent after EXTENT using the \"e\" order.\n\
  3050. If EXTENT is a buffer, return the first extent in the buffer.")
  3051.   (extent)
  3052.    Lisp_Object extent;
  3053. {
  3054.   Lisp_Object val;
  3055.   EXTENT next;
  3056.  
  3057.   if (EXTENTP (extent))
  3058.     next = extent_e_next (decode_extent (extent, DE_MUST_BE_ATTACHED));
  3059.   else
  3060.     next = extent_e_first (decode_extent_object (extent));
  3061.  
  3062.   if (!next)
  3063.     return (Qnil);
  3064.   XSETEXTENT (val, next);
  3065.   return (val);
  3066. }
  3067.  
  3068. DEFUN ("previous-e-extent", Fprevious_e_extent, Sprevious_e_extent, 1, 1, 0,
  3069.        "Find last extent before EXTENT using the \"e\" order.\n\
  3070. If EXTENT is a buffer return the last extent in the buffer.\n\
  3071. This function is analogous to `next-e-extent'.")
  3072.   (extent)
  3073.    Lisp_Object extent;
  3074. {
  3075.   Lisp_Object val;
  3076.   EXTENT prev;
  3077.  
  3078.   if (EXTENTP (extent))
  3079.     prev = extent_e_previous (decode_extent (extent, DE_MUST_BE_ATTACHED));
  3080.   else
  3081.     prev = extent_e_last (decode_extent_object (extent));
  3082.  
  3083.   if (!prev)
  3084.     return (Qnil);
  3085.   XSETEXTENT (val, prev);
  3086.   return (val);
  3087. }
  3088.  
  3089. #endif
  3090.  
  3091. DEFUN ("next-extent-change", Fnext_extent_change, Snext_extent_change,
  3092.        1, 2, 0,
  3093.   "Return the next position after POS where an extent begins or ends.\n\
  3094. If POS is at the end of the buffer, POS will be returned; otherwise a\n\
  3095.  position greater than POS will always be returned.\n\
  3096. If BUFFER is nil, the current buffer is assumed.")
  3097.   (pos, buffer)
  3098.      Lisp_Object pos, buffer;
  3099. {
  3100.   Lisp_Object obj = decode_extent_object (buffer);
  3101.   Bytind bpos;
  3102.  
  3103.   if (BUFFERP (obj))
  3104.     bpos = get_bytind (XBUFFER (obj), pos, GB_ALLOW_PAST_ACCESSIBLE);
  3105.   else
  3106.     {
  3107.       assert (STRINGP (obj));
  3108.       bpos = get_string_bytepos (obj, pos);
  3109.     }
  3110.   bpos = extent_find_end_of_run (obj, bpos, 1);
  3111.   return make_number (extent_object_bytind_to_bufpos (obj, bpos));
  3112. }
  3113.  
  3114. DEFUN ("previous-extent-change", Fprevious_extent_change,
  3115.        Sprevious_extent_change, 1, 2, 0,
  3116.   "Return the last position before POS where an extent begins or ends.\n\
  3117. If POS is at the beginning of the buffer, POS will be returned; otherwise a\n\
  3118.  position less than POS will always be returned.\n\
  3119. If BUFFER is nil, the current buffer is assumed.")
  3120.   (pos, buffer)
  3121.      Lisp_Object pos, buffer;
  3122. {
  3123.   Lisp_Object obj = decode_extent_object (buffer);
  3124.   Bytind bpos;
  3125.  
  3126.   if (BUFFERP (obj))
  3127.     bpos = get_bytind (XBUFFER (obj), pos, GB_ALLOW_PAST_ACCESSIBLE);
  3128.   else
  3129.     {
  3130.       assert (STRINGP (obj));
  3131.       bpos = get_string_bytepos (obj, pos);
  3132.     }
  3133.   bpos = extent_find_beginning_of_run (obj, bpos, 1);
  3134.   return make_number (extent_object_bytind_to_bufpos (obj, bpos));
  3135. }
  3136.  
  3137.  
  3138. /************************************************************************/
  3139. /*                parent and children stuff            */
  3140. /************************************************************************/
  3141.  
  3142. DEFUN ("extent-parent", Fextent_parent, Sextent_parent, 1, 1, 0,
  3143.        "Return the parent (if any) of EXTENT.\n\
  3144. If an extent has a parent, it derives all its properties from that extent\n\
  3145. and has no properties of its own.  It is possible for an extent's parent\n\
  3146. to itself have a parent.")
  3147.      (extent)
  3148.      Lisp_Object extent;
  3149. /* do I win the prize for the strangest split infinitive? */
  3150. {
  3151.   EXTENT e = decode_extent (extent, 0);
  3152.   return extent_parent (e);
  3153. }
  3154.  
  3155. DEFUN ("extent-children", Fextent_children, Sextent_children, 1, 1, 0,
  3156.        "Return a list of the children (if any) of EXTENT.\n\
  3157. The children of an extent are all those extents whose parent is that extent.\n\
  3158. This function does not recursively trace children of children.")
  3159.      (extent)
  3160.      Lisp_Object extent;
  3161. {
  3162.   EXTENT e = decode_extent (extent, 0);
  3163.   return Fcopy_sequence (extent_children (e));
  3164. }
  3165.  
  3166. static void
  3167. remove_extent_from_children_list (EXTENT e, Lisp_Object child)
  3168. {
  3169.   Lisp_Object children = extent_children (e);
  3170. #ifdef ERROR_CHECK_EXTENTS
  3171.   assert (!NILP (memq_no_quit (child, children)));
  3172. #endif
  3173.   set_extent_ancestor_aux_field (e, children, delq_no_quit (child, children));
  3174. }
  3175.  
  3176. static void
  3177. add_extent_to_children_list (EXTENT e, Lisp_Object child)
  3178. {
  3179.   Lisp_Object children = extent_children (e);
  3180. #ifdef ERROR_CHECK_EXTENTS
  3181.   assert (NILP (memq_no_quit (child, children)));
  3182. #endif
  3183.   set_extent_ancestor_aux_field (e, children, Fcons (child, children));
  3184. }
  3185.  
  3186. DEFUN ("set-extent-parent", Fset_extent_parent, Sset_extent_parent, 2, 2, 0,
  3187.        "Set the parent of EXTENT to PARENT (may be nil).\n\
  3188. See `extent-parent'.")
  3189.      (extent, parent)
  3190.      Lisp_Object extent, parent;
  3191. {
  3192.   EXTENT e = decode_extent (extent, 0);
  3193.   Lisp_Object cur_parent = extent_parent (e);
  3194.   Lisp_Object rest;
  3195.  
  3196.   XSETEXTENT (extent, e);
  3197.   if (!NILP (parent))
  3198.     CHECK_LIVE_EXTENT (parent, 1);
  3199.   if (EQ (parent, cur_parent))
  3200.     return Qnil;
  3201.   for (rest = parent; !NILP (rest); rest = extent_parent (XEXTENT (rest)))
  3202.     if (EQ (rest, extent))
  3203.       signal_simple_error ("Circular parent chain would result", extent);
  3204.   if (NILP (parent))
  3205.     {
  3206.       remove_extent_from_children_list (XEXTENT (cur_parent), extent);
  3207.       set_extent_ancestor_aux_field (e, parent, Qnil);
  3208.       e->flags.has_parent = 0;
  3209.     }
  3210.   else
  3211.     {
  3212.       add_extent_to_children_list (XEXTENT (parent), extent);
  3213.       set_extent_ancestor_aux_field (e, parent, parent);
  3214.       e->flags.has_parent = 1;
  3215.     }
  3216.   /* changing the parent also changes the properties of all children. */
  3217.   extent_maybe_changed_for_redisplay (e, 1);
  3218.   return Qnil;
  3219. }
  3220.  
  3221.  
  3222. /************************************************************************/
  3223. /*                basic extent mutators                */
  3224. /************************************************************************/
  3225.  
  3226. /* Note:  If you track non-duplicable extents by undo, you'll get bogus
  3227.    undo records for transient extents via update-extent.
  3228.    For example, query-replace will do this.
  3229.  */
  3230.  
  3231. static void
  3232. set_extent_endpoints_1 (EXTENT extent, Memind start, Memind end)
  3233. {
  3234. #ifdef ERROR_CHECK_EXTENTS
  3235.   Lisp_Object obj = extent_object (extent);
  3236.  
  3237.   assert (start <= end);
  3238.   if (BUFFERP (obj))
  3239.     {
  3240.       assert (valid_memind_p (XBUFFER (obj), start));
  3241.       assert (valid_memind_p (XBUFFER (obj), end));
  3242.     }
  3243. #endif
  3244.  
  3245.   /* Optimization: if the extent is already where we want it to be,
  3246.      do nothing. */
  3247.   if (!extent_detached_p (extent) && extent_start (extent) == start &&
  3248.       extent_end (extent) == end)
  3249.     return;
  3250.  
  3251.   if (extent_detached_p (extent))
  3252.     {
  3253.       if (extent_duplicable_p (extent))
  3254.     {
  3255.       Lisp_Object extent_obj;
  3256.       XSETEXTENT (extent_obj, extent);
  3257.       record_extent (extent_obj, 1);
  3258.     }
  3259.     }
  3260.   else
  3261.     extent_detach (extent);
  3262.  
  3263.   set_extent_start (extent, start);
  3264.   set_extent_end (extent, end);
  3265.   extent_attach (extent);
  3266. }
  3267.  
  3268. static void
  3269. set_extent_endpoints (EXTENT extent, Bytind s, Bytind e)
  3270. {
  3271.   Lisp_Object obj = extent_object (extent);
  3272.   Memind start, end;
  3273.  
  3274.   assert (!NILP (obj));
  3275.   start = s < 0 ? extent_start (extent) :
  3276.     extent_object_bytind_to_memind (obj, s);
  3277.   end = e < 0 ? extent_end (extent) :
  3278.     extent_object_bytind_to_memind (obj, e);
  3279.   set_extent_endpoints_1 (extent, start, end);
  3280. }
  3281.  
  3282. static void
  3283. set_extent_openness (EXTENT extent, int start_open, int end_open)
  3284. {
  3285.   if (start_open == -1)
  3286.     start_open = extent_start_open_p (extent);
  3287.   if (end_open == -1)
  3288.     end_open = extent_end_open_p (extent);
  3289.   extent_start_open_p (extent) = start_open;
  3290.   extent_end_open_p (extent) = end_open;
  3291.   /* changing the open/closedness of an extent does not affect
  3292.      redisplay. */
  3293. }
  3294.  
  3295. void
  3296. set_extent_face (EXTENT extent, Lisp_Object face)
  3297. {
  3298.   extent = extent_ancestor (extent);
  3299.   extent_face (extent) = face;
  3300.   extent_changed_for_redisplay (extent, 1);
  3301. }
  3302.  
  3303. static void
  3304. set_extent_invisible (EXTENT extent, int flag)
  3305. {
  3306.   if (extent_invisible_p (extent) != flag)
  3307.     {
  3308.       extent_invisible_p (extent) = flag;
  3309.       extent_changed_for_redisplay (extent, 1);
  3310.     }
  3311. }
  3312.  
  3313. static void
  3314. set_extent_intangible (EXTENT extent, int flag)
  3315. {
  3316.   if (extent_intangible_p (extent) != flag)
  3317.     {
  3318.       extent_intangible_p (extent) = flag;
  3319.       extent_changed_for_redisplay (extent, 1);
  3320.     }
  3321. }
  3322.  
  3323. static EXTENT
  3324. make_extent_internal (Lisp_Object object, Bytind from, Bytind to)
  3325. {
  3326.   EXTENT extent;
  3327.   
  3328.   extent = make_extent_detached (object);
  3329.   set_extent_endpoints (extent, from, to);
  3330.   return extent;
  3331. }
  3332.  
  3333. static EXTENT
  3334. copy_extent (EXTENT original, Bytind from, Bytind to, Lisp_Object object)
  3335. {
  3336.   EXTENT e;
  3337.  
  3338.   e = make_extent_detached (object);
  3339.   if (from != 0)
  3340.     set_extent_endpoints (e, from, to);
  3341.  
  3342.   e->plist = Fcopy_sequence (original->plist);
  3343.   memcpy (&e->flags, &original->flags, sizeof (e->flags));
  3344.   if (e->flags.has_aux)
  3345.     {
  3346.       /* also need to copy the aux struct.  It won't work for
  3347.      this extent to share the same aux struct as the original
  3348.      one. */
  3349.       struct extent_auxiliary *data =
  3350.     alloc_lcrecord (sizeof (struct extent_auxiliary),
  3351.             lrecord_extent_auxiliary);
  3352.  
  3353.       copy_lcrecord (data, XEXTENT_AUXILIARY (XCAR (original->plist)));
  3354.       XSETEXTENT_AUXILIARY (XCAR (e->plist), data);
  3355.     }
  3356.  
  3357.   {
  3358.     /* we may have just added another child to the parent extent. */
  3359.     Lisp_Object parent = extent_parent (e);
  3360.     if (!NILP (parent))
  3361.       {
  3362.     Lisp_Object extent;
  3363.     XSETEXTENT (extent, e);
  3364.     add_extent_to_children_list (XEXTENT (parent), extent);
  3365.       }
  3366.   }
  3367.       
  3368.   /* #### it's still unclear to me that this Energize-specific junk
  3369.      needs to be in here.  Just use the general mechanisms, or fix
  3370.      them up! --ben */
  3371. #ifdef ENERGIZE
  3372.   if (energize_extent_data (original))
  3373.     {
  3374.       extent_plist (e) = Qnil; /* slightly antisocial... */
  3375.       restore_energize_extent_state (e);
  3376.     }
  3377. #endif
  3378.  
  3379.   return e;
  3380. }
  3381.  
  3382. Lisp_Object Fset_extent_parent (Lisp_Object, Lisp_Object);
  3383.  
  3384. static void 
  3385. destroy_extent (EXTENT extent) 
  3386. {
  3387.   Lisp_Object rest;
  3388.   Lisp_Object extent_obj = Qnil;
  3389.  
  3390.   if (!extent_detached_p (extent))
  3391.     extent_detach (extent);
  3392.   /* disassociate the extent from its children and parent */
  3393.   LIST_LOOP (rest, extent_children (extent))
  3394.     Fset_extent_parent (XCAR (rest), Qnil);
  3395.   XSETEXTENT (extent_obj, extent);
  3396.   Fset_extent_parent (extent_obj, Qnil);
  3397.   /* mark the extent as destroyed */
  3398.   extent_object (extent) = Qt;
  3399. }
  3400.  
  3401. void
  3402. init_buffer_extents (struct buffer *b)
  3403. {
  3404.   b->extents = make_extent_list ();
  3405.   b->soe = make_soe ();
  3406. }
  3407.  
  3408. void
  3409. uninit_buffer_extents (struct buffer *b)
  3410. {
  3411.   int i;
  3412.  
  3413.   free_soe (b->soe);
  3414.   b->soe = 0;
  3415.   for (i = 0; i < extent_list_num_els (b->extents); i++)
  3416.     {
  3417.       EXTENT e = extent_list_at (b->extents, i, 0);
  3418.       /* No need to do detach_extent(). (Anyway, the SOE has already
  3419.      been freed.) Just nuke the damn things. */
  3420.       set_extent_start (e, 0);
  3421.       set_extent_end (e, 0);
  3422.       /* Don't destroy the extent here -- there may still be extent
  3423.      replicas pointing to the extent. */
  3424.     }
  3425.   free_extent_list (b->extents);
  3426.   b->extents = 0;
  3427. }
  3428.  
  3429. DEFUN ("make-extent", Fmake_extent, Smake_extent, 2, 3, 0,
  3430.        "Make an extent for the range [FROM, TO) in BUFFER-OR-STRING.\n\
  3431. BUFFER-OR-STRING defaults to the current buffer. (Note: Currently\n\
  3432. extents over strings are not supported, but will be in the future.)\n\
  3433. Insertions at point TO will be outside of the extent; insertions at\n\
  3434. FROM will be inside the extent, causing the extent to grow. (This is\n\
  3435. the same way that markers behave.) You can change the behavior of\n\
  3436. insertions at the endpoints using `set-extent-property'.  The extent is\n\
  3437. initially detached if both FROM and TO are nil, and in this case\n\
  3438. BUFFER-OR-STRING defaults to nil, meaning the extent is in no buffer\n\
  3439. and no string.")
  3440.   (from, to, buffer_or_string)
  3441.    Lisp_Object from, to, buffer_or_string;
  3442. {
  3443.   Lisp_Object extent_obj = Qnil;
  3444.   Lisp_Object obj;
  3445.  
  3446.   if (STRINGP (buffer_or_string))
  3447.     strings_not_supported ();
  3448.   obj = decode_extent_object (buffer_or_string);
  3449.   if (NILP (from) && NILP (to))
  3450.     {
  3451.       if (NILP (buffer_or_string))
  3452.     obj = Qnil;
  3453.       XSETEXTENT (extent_obj, make_extent_detached (obj));
  3454.     }
  3455.   else
  3456.     {
  3457.       Bytind start, end;
  3458.       
  3459.       if (STRINGP (obj))
  3460.     get_string_range (obj, from, to, &start, &end);
  3461.       else
  3462.     get_bufrange_bytind (XBUFFER (obj), from, to, &start, &end,
  3463.                  GB_ALLOW_PAST_ACCESSIBLE);
  3464.       XSETEXTENT (extent_obj, make_extent_internal (obj, start, end));
  3465.     }
  3466.   return extent_obj;
  3467. }
  3468.  
  3469. DEFUN ("copy-extent", Fcopy_extent, Scopy_extent, 1, 2, 0,
  3470.  "Make a copy of EXTENT.  It is initially detached.\n\
  3471. Optional argument BUFFER-OR-STRING defaults to EXTENT's buffer or string.")
  3472.   (extent, buffer_or_string)
  3473.    Lisp_Object extent, buffer_or_string;
  3474. {
  3475.   EXTENT ext = decode_extent (extent, 0);
  3476.  
  3477.   if (NILP (buffer_or_string))
  3478.     buffer_or_string = extent_object (ext);
  3479.   else
  3480.     buffer_or_string = decode_extent_object (buffer_or_string);
  3481.  
  3482.   XSETEXTENT (extent, copy_extent (ext, 0, 0, buffer_or_string));
  3483.   return extent;
  3484. }
  3485.  
  3486. DEFUN ("delete-extent", Fdelete_extent, Sdelete_extent, 1, 1, 0,
  3487.  "Remove EXTENT from its buffer and destroy it.\n\
  3488. This does not modify the buffer's text, only its display properties.\n\
  3489. The extent cannot be used thereafter.")
  3490.   (extent)
  3491.    Lisp_Object extent;
  3492. {
  3493.   EXTENT ext;
  3494.  
  3495.   /* We do not call decode_extent() here because already-destroyed
  3496.      extents are OK. */
  3497.   CHECK_EXTENT (extent, 0);
  3498.   ext = XEXTENT (extent);
  3499.  
  3500.   if (!EXTENT_LIVE_P (ext))
  3501.     return Qnil;
  3502.   destroy_extent (ext);
  3503.   return Qnil;
  3504. }
  3505.  
  3506. DEFUN ("detach-extent", Fdetach_extent, Sdetach_extent, 1, 1, 0,
  3507.    "Remove EXTENT from its buffer in such a way that it can be re-inserted.\n\
  3508. An extent is also detached when all of its characters are all killed by a\n\
  3509. deletion, unless its `detachable' property has been unset.\n\
  3510. \n\
  3511. Extents which have the `duplicable' attribute are tracked by the undo\n\
  3512. mechanism.  Detachment via `detach-extent' and string deletion is recorded,\n\
  3513. as is attachment via `insert-extent' and string insertion.  Extent motion,\n\
  3514. face changes, and attachment via `make-extent' and `set-extent-endpoints'\n\
  3515. are not recorded.  This means that extent changes which are to be undo-able\n\
  3516. must be performed by character editing, or by insertion and detachment of\n\
  3517. duplicable extents.")
  3518.   (extent)
  3519.    Lisp_Object extent;
  3520. {
  3521.   EXTENT ext = decode_extent (extent, 0);
  3522.  
  3523.   if (extent_detached_p (ext))
  3524.     return extent;
  3525.   if (extent_duplicable_p (ext))
  3526.     record_extent (extent, 0);
  3527.   extent_detach (ext);
  3528.  
  3529.   return extent;
  3530. }
  3531.  
  3532. DEFUN ("set-extent-endpoints", Fset_extent_endpoints, Sset_extent_endpoints,
  3533.        3, 3, 0,
  3534.        "Set the endpoints of EXTENT to START, END.\n\
  3535. If START and END are null, call detach-extent on EXTENT.\n\
  3536. See documentation on `detach-extent' for a discussion of undo recording.")
  3537.   (extent, start, end)
  3538.    Lisp_Object extent, start, end;
  3539. {
  3540.   EXTENT ext;
  3541.   Bytind s, e;
  3542.   Lisp_Object obj;
  3543.  
  3544.   if (NILP (start) && NILP (end))
  3545.     return Fdetach_extent (extent);
  3546.  
  3547.   ext = decode_extent (extent, DE_MUST_HAVE_BUFFER);
  3548.   obj = extent_object (ext);
  3549.   if (STRINGP (obj))
  3550.     get_string_range (obj, start, end, &s, &e);
  3551.   else
  3552.     get_bufrange_bytind (XBUFFER (obj), start, end, &s, &e,
  3553.              GB_ALLOW_PAST_ACCESSIBLE);
  3554.   set_extent_endpoints (ext, s, e);
  3555.   return extent;
  3556. }
  3557.  
  3558.  
  3559. /************************************************************************/
  3560. /*                   mapping over extents                */
  3561. /************************************************************************/
  3562.  
  3563. static unsigned int
  3564. decode_map_extents_flags (Lisp_Object flags)
  3565. {
  3566.   unsigned int retval = 0;
  3567.   unsigned int all_extents_specified = 0;
  3568.   unsigned int in_region_specified = 0;
  3569.  
  3570.   if (EQ (flags, Qt)) /* obsoleteness compatibility */
  3571.     return ME_END_CLOSED;
  3572.   if (EQ (flags, Qnil))
  3573.     return 0;
  3574.   if (SYMBOLP (flags))
  3575.     flags = Fcons (flags, Qnil);
  3576.   while (!NILP (flags))
  3577.     {
  3578.       Lisp_Object sym;
  3579.       CHECK_CONS (flags, 0);
  3580.       sym = XCAR (flags);
  3581.       CHECK_SYMBOL (sym, 0);
  3582.       if (EQ (sym, Qall_extents_closed) || EQ (sym, Qall_extents_open) ||
  3583.       EQ (sym, Qall_extents_closed_open) ||
  3584.       EQ (sym, Qall_extents_open_closed))
  3585.     {
  3586.       if (all_extents_specified)
  3587.         error ("Only one `all-extents-*' flag may be specified");
  3588.       all_extents_specified = 1;
  3589.     }
  3590.       if (EQ (sym, Qstart_in_region) || EQ (sym, Qend_in_region) ||
  3591.       EQ (sym, Qstart_and_end_in_region) ||
  3592.       EQ (sym, Qstart_or_end_in_region))
  3593.     {
  3594.       if (in_region_specified)
  3595.         error ("Only one `*-in-region' flag may be specified");
  3596.       in_region_specified = 1;
  3597.     }
  3598.  
  3599.       /* I do so love that conditional operator ... */
  3600.       retval |=
  3601.     EQ (sym, Qend_closed) ? ME_END_CLOSED :
  3602.     EQ (sym, Qstart_open) ? ME_START_OPEN :
  3603.     EQ (sym, Qall_extents_closed) ? ME_ALL_EXTENTS_CLOSED :
  3604.     EQ (sym, Qall_extents_open) ? ME_ALL_EXTENTS_OPEN :
  3605.     EQ (sym, Qall_extents_closed_open) ? ME_ALL_EXTENTS_CLOSED_OPEN :
  3606.     EQ (sym, Qall_extents_open_closed) ? ME_ALL_EXTENTS_OPEN_CLOSED :
  3607.     EQ (sym, Qstart_in_region) ? ME_START_IN_REGION :
  3608.     EQ (sym, Qend_in_region) ? ME_END_IN_REGION :
  3609.     EQ (sym, Qstart_and_end_in_region) ? ME_START_AND_END_IN_REGION :
  3610.     EQ (sym, Qstart_or_end_in_region) ? ME_START_OR_END_IN_REGION :
  3611.     EQ (sym, Qnegate_in_region) ? ME_NEGATE_IN_REGION :
  3612.     (signal_simple_error ("Invalid `map-extents' flag", sym), 0);
  3613.  
  3614.       flags = XCDR (flags);
  3615.     }
  3616.   return retval;
  3617. }
  3618.  
  3619. DEFUN ("extent-in-region-p", Fextent_in_region_p, Sextent_in_region_p, 1, 4, 0,
  3620.        "Return whether EXTENT overlaps a specified region.\n\
  3621. This is equivalent to whether `map-extents' would visit EXTENT when called\n\
  3622. with these args.")
  3623.      (extent, from, to, flags)
  3624.      Lisp_Object extent, from, to, flags;
  3625. {
  3626.   EXTENT ext;
  3627.   Lisp_Object obj;
  3628.   Bytind start, end;
  3629.  
  3630.   ext = decode_extent (extent, DE_MUST_BE_ATTACHED);
  3631.   obj = extent_object (ext);
  3632.   if (STRINGP (obj))
  3633.     strings_not_supported ();
  3634.   get_bufrange_bytind (XBUFFER (obj), from, to, &start, &end, GB_ALLOW_NIL |
  3635.                GB_ALLOW_PAST_ACCESSIBLE);
  3636.  
  3637.   if (extent_in_region_p (ext, start, end, decode_map_extents_flags (flags)))
  3638.     return Qt;
  3639.   return Qnil;
  3640. }
  3641.  
  3642. struct slow_map_extents_arg
  3643. {
  3644.   Lisp_Object map_arg;
  3645.   Lisp_Object map_routine;
  3646.   Lisp_Object result;
  3647.   Lisp_Object property;
  3648.   Lisp_Object value;
  3649. };
  3650.  
  3651. static int
  3652. slow_map_extents_function (EXTENT extent, void *arg)
  3653. {
  3654.   /* This function can GC */
  3655.   struct slow_map_extents_arg *closure = (struct slow_map_extents_arg *) arg;
  3656.   Lisp_Object extent_obj;
  3657.  
  3658.   XSETEXTENT (extent_obj, extent);
  3659.  
  3660.   /* make sure this extent qualifies according to the PROPERTY
  3661.      and VALUE args */
  3662.  
  3663.   if (!NILP (closure->property))
  3664.     {
  3665.       Lisp_Object value = Fextent_property (extent_obj, closure->property);
  3666.       if ((NILP (closure->value) && NILP (value)) ||
  3667.       (!NILP (closure->value) && !EQ (value, closure->value)))
  3668.     return 0;
  3669.     }
  3670.  
  3671.   closure->result = call2 (closure->map_routine, extent_obj,
  3672.                closure->map_arg);
  3673.   if (NILP (closure->result))
  3674.     return 0;
  3675.   else
  3676.     return 1;
  3677. }
  3678.  
  3679. /* This comment supplies the doc string for map-extents.
  3680.    for make-docfile to see.  We cannot put this in the real DEFUN
  3681.    due to limits in the Unix cpp.
  3682.  
  3683.  
  3684. DEFUN ("map-extents", Fmap_extents, Smap_extents, 1, 8, 0,
  3685.        "Map FUNCTION over the extents which overlap a region in BUFFER.\n\
  3686. The region is normally bounded by [FROM, TO) (i.e. the beginning of the\n\
  3687. region is closed and the end of the region is open), but this can be\n\
  3688. changed with the FLAGS argument (see below for a complete discussion).\n\
  3689. \n\
  3690. FUNCTION is called with the arguments (extent, MAPARG).  The arguments\n\
  3691. BUFFER, FROM, TO, MAPARG, and CLOSED-END are all optional and default to\n\
  3692. the current buffer, the beginning of BUFFER, the end of BUFFER, nil, and\n\
  3693. nil, respectively.  MAP-EXTENTS returns the first non-nil result produced\n\
  3694. by FUNCTION, and no more calls to FUNCTION are made after it returns\n\
  3695. non-nil.\n\
  3696. \n\
  3697. If BUFFER is an extent, FROM and TO default to the extent's endpoints,\n\
  3698. and the mapping omits that extent and its predecessors.  This feature\n\
  3699. supports restarting a loop based on `map-extents'.\n\
  3700. \n\
  3701. An extent overlaps the region if there is any point in the extent that is\n\
  3702. also in the region. (For the purpose of overlap, zero-length extents and\n\
  3703. regions are treated as closed on both ends regardless of their endpoints'\n\
  3704. specified open/closedness.) Note that the endpoints of an extent or region\n\
  3705. are considered to be in that extent or region if and only if the\n\
  3706. corresponding end is closed.  For example, the extent [5,7] overlaps the\n\
  3707. region [2,5] because 5 is in both the extent and the region.  However, (5,7]\n\
  3708. does not overlap [2,5] because 5 is not in the extent, and neither [5,7] nor\n\
  3709. (5,7] overlaps the region [2,5) because 5 is not in the region.\n\
  3710. \n\
  3711. The optional FLAGS can be a symbol or a list of one or more symbols,\n\
  3712. modifying the behavior of `map-extents'.  Allow symbols are:\n\
  3713. \n\
  3714. end-closed        The region's end is closed.\n\
  3715. \n\
  3716. start-open        The region's start is open.\n\
  3717. \n\
  3718. all-extents-closed    Treat all extents as closed on both ends for the\n\
  3719.             purpose of determining whether they overlap the\n\
  3720.             region, irrespective of their actual open- or\n\
  3721.             closedness.\n\
  3722. all-extents-open    Treat all extents as open on both ends.\n\
  3723. all-extents-closed-open    Treat all extents as start-closed, end-open.\n\
  3724. all-extents-open-closed    Treat all extents as start-open, end-closed.\n\
  3725. \n\
  3726. start-in-region        In addition to the above conditions for extent\n\
  3727.             overlap, the extent's start position must lie within\n\
  3728.             the specified region.  Note that, for this\n\
  3729.             condition, open start positions are treated as if\n\
  3730.             0.5 was added to the endpoint's value, and open\n\
  3731.             end positions are treated as if 0.5 was subtracted\n\
  3732.             from the endpoint's value.\n\
  3733. end-in-region        The extent's end position must lie within the
  3734.             region.\n\
  3735. start-and-end-in-region    Both the extent's start and end positions must lie\n\
  3736.             within the region.\n\
  3737. start-or-end-in-region    Either the extent's start or end position must lie\n\
  3738.             within the region.\n\
  3739. \n\
  3740. negate-in-region    The condition specified by a `*-in-region' flag\n\
  3741.             must NOT hold for the extent to be considered.\n\
  3742. \n\
  3743. \n\
  3744. At most one of `all-extents-closed', `all-extents-open',\n\
  3745. `all-extents-closed-open', and `all-extents-open-closed' may be specified.\n\
  3746. \n\
  3747. At most one of `start-in-region', `end-in-region',\n\
  3748. `start-and-end-in-region', and `start-or-end-in-region' may be specified.\n\
  3749. \n\
  3750. If optional arg PROPERTY is non-nil, only extents with that property set\n\
  3751. on them will be visited.  If optional arg VALUE is non-nil, only extents\n\
  3752. whose value for that property is `eq' to VALUE will be visited.")
  3753.   (function, buffer, from, to, maparg, flags, property, value)
  3754.  
  3755. */
  3756.  
  3757. DEFUN ("map-extents", Fmap_extents, Smap_extents, 1, 8, 0, 0)
  3758.   (function, buffer, from, to, maparg, flags, property, value)
  3759.   Lisp_Object function, buffer, from, to, maparg, flags, property, value;
  3760. {
  3761.   /* This function can GC */
  3762.   struct slow_map_extents_arg closure;
  3763.   unsigned int me_flags;
  3764.   Bytind start, end;
  3765.   struct gcpro gcpro1, gcpro2, gcpro3;
  3766.   EXTENT after = 0;
  3767.   struct buffer *b;
  3768.  
  3769.   if (EXTENTP (buffer))
  3770.     {
  3771.       after = decode_extent (buffer, DE_MUST_BE_ATTACHED);
  3772.       b = XBUFFER (extent_object (after));
  3773.       if (NILP (from)) from = Fextent_start_position (buffer);
  3774.       if (NILP (to)) to = Fextent_end_position (buffer);
  3775.     }
  3776.   else
  3777.     b = decode_buffer (buffer, 0);
  3778.  
  3779.   get_bufrange_bytind (b, from, to, &start, &end, GB_ALLOW_NIL |
  3780.                GB_ALLOW_PAST_ACCESSIBLE);
  3781.  
  3782.   me_flags = decode_map_extents_flags (flags);
  3783.  
  3784.   if (!NILP (property))
  3785.     CHECK_SYMBOL (property, 6);
  3786.  
  3787.   GCPRO3 (function, maparg, buffer);
  3788.  
  3789.   closure.map_arg = maparg;
  3790.   closure.map_routine = function;
  3791.   closure.result = Qnil;
  3792.   closure.property = property;
  3793.   closure.value = value;
  3794.  
  3795.   map_extents_bytind (start, end, slow_map_extents_function,
  3796.               (void *) &closure, make_buffer (b), after,
  3797.               /* You never know what the user might do ... */
  3798.               me_flags | ME_MIGHT_CALL_ELISP);
  3799.  
  3800.   UNGCPRO;
  3801.   return closure.result;
  3802. }
  3803.  
  3804.  
  3805. /************************************************************************/
  3806. /*        mapping over extents -- other functions            */
  3807. /************************************************************************/
  3808.  
  3809. /* ------------------------------- */
  3810. /*      map-extent-children        */
  3811. /* ------------------------------- */
  3812.  
  3813. struct slow_map_extent_children_arg
  3814. {
  3815.   Lisp_Object map_arg;
  3816.   Lisp_Object map_routine;
  3817.   Lisp_Object result;
  3818.   Lisp_Object property;
  3819.   Lisp_Object value;
  3820.   Bytind start_min;
  3821.   Bytind prev_start;
  3822.   Bytind prev_end;
  3823. };
  3824.  
  3825. static int
  3826. slow_map_extent_children_function (EXTENT extent, void *arg)
  3827. {
  3828.   /* This function can GC */
  3829.   struct slow_map_extent_children_arg *closure =
  3830.     (struct slow_map_extent_children_arg *) arg;
  3831.   Lisp_Object extent_obj;
  3832.   Bytind start = extent_endpoint_bytind (extent, 0);
  3833.   Bytind end = extent_endpoint_bytind (extent, 1);
  3834.   /* Make sure the extent starts inside the region of interest,
  3835.      rather than just overlaps it.
  3836.      */
  3837.   if (start < closure->start_min)
  3838.     return 0;
  3839.   /* Make sure the extent is not a child of a previous visited one.
  3840.      We know already, because of extent ordering,
  3841.      that start >= prev_start, and that if
  3842.      start == prev_start, then end <= prev_end.
  3843.      */
  3844.   if (start == closure->prev_start)
  3845.     {
  3846.       if (end < closure->prev_end)
  3847.     return 0;
  3848.     }
  3849.   else /* start > prev_start */
  3850.     {
  3851.       if (start < closure->prev_end)
  3852.     return 0;
  3853.       /* corner case:  prev_end can be -1 if there is no prev */
  3854.     }
  3855.   XSETEXTENT (extent_obj, extent);
  3856.  
  3857.   /* make sure this extent qualifies according to the PROPERTY
  3858.      and VALUE args */
  3859.  
  3860.   if (!NILP (closure->property))
  3861.     {
  3862.       Lisp_Object value = Fextent_property (extent_obj, closure->property);
  3863.       if ((NILP (closure->value) && NILP (value)) ||
  3864.       (!NILP (closure->value) && !EQ (value, closure->value)))
  3865.     return 0;
  3866.     }
  3867.  
  3868.   closure->result = call2 (closure->map_routine, extent_obj,
  3869.                closure->map_arg);
  3870.  
  3871.   /* Since the callback may change the buffer, compute all stored
  3872.      buffer positions here.
  3873.      */
  3874.   closure->start_min = -1;    /* no need for this any more */
  3875.   closure->prev_start = extent_endpoint_bytind (extent, 0);
  3876.   closure->prev_end = extent_endpoint_bytind (extent, 1);
  3877.  
  3878.   if (NILP (closure->result))
  3879.     return 0;
  3880.   else
  3881.     return 1;
  3882. }
  3883.  
  3884. DEFUN ("map-extent-children", Fmap_extent_children, Smap_extent_children,
  3885.        1, 8, 0,
  3886.        "Map FUNCTION over the extents in the region from FROM to TO.\n\
  3887. FUNCTION is called with arguments (extent, MAPARG).  See `map-extents'\n\
  3888. for a full discussion of the arguments FROM, TO, and FLAGS.\n\
  3889. \n\
  3890. The arguments are the same as for `map-extents', but this function differs\n\
  3891. in that it only visits extents which start in the given region, and also\n\
  3892. in that, after visiting an extent E, it skips all other extents which start\n\
  3893. inside E but end before E's end.\n\
  3894. \n\
  3895. Thus, this function may be used to walk a tree of extents in a buffer:\n\
  3896.     (defun walk-extents (buffer &optional ignore)\n\
  3897.      (map-extent-children 'walk-extents buffer))")
  3898.      (function, buffer, from, to, maparg, flags, property, value)
  3899.      Lisp_Object function, buffer, from, to, maparg, flags, property, value;
  3900. {
  3901.   /* This function can GC */
  3902.   struct slow_map_extent_children_arg closure;
  3903.   unsigned int me_flags;
  3904.   Bytind start, end;
  3905.   struct gcpro gcpro1, gcpro2, gcpro3;
  3906.   EXTENT after = 0;
  3907.   struct buffer *b;
  3908.  
  3909.   if (EXTENTP (buffer))
  3910.     {
  3911.       after = decode_extent (buffer, DE_MUST_BE_ATTACHED);
  3912.       b = XBUFFER (extent_object (after));
  3913.       if (NILP (from)) from = Fextent_start_position (buffer);
  3914.       if (NILP (to)) to = Fextent_end_position (buffer);
  3915.     }
  3916.   else
  3917.     b = decode_buffer (buffer, 0);
  3918.  
  3919.   get_bufrange_bytind (b, from, to, &start, &end, GB_ALLOW_NIL |
  3920.                GB_ALLOW_PAST_ACCESSIBLE);
  3921.  
  3922.   me_flags = decode_map_extents_flags (flags);
  3923.  
  3924.   if (!NILP (property))
  3925.     CHECK_SYMBOL (property, 6);
  3926.  
  3927.   GCPRO3 (function, maparg, buffer);
  3928.  
  3929.   closure.map_arg = maparg;
  3930.   closure.map_routine = function;
  3931.   closure.result = Qnil;
  3932.   closure.property = property;
  3933.   closure.value = value;
  3934.   closure.start_min = start;
  3935.   closure.prev_start = -1;
  3936.   closure.prev_end = -1;
  3937.   map_extents_bytind (start, end, slow_map_extent_children_function,
  3938.               (void *) &closure, make_buffer (b), after,
  3939.               /* You never know what the user might do ... */
  3940.               me_flags | ME_MIGHT_CALL_ELISP);
  3941.  
  3942.   UNGCPRO;
  3943.   return closure.result;
  3944. }
  3945.  
  3946. /* ------------------------------- */
  3947. /*             extent-at           */
  3948. /* ------------------------------- */
  3949.  
  3950. /* find "smallest" matching extent containing pos -- (flag == 0) means 
  3951.    all extents match, else (EXTENT_FLAGS (extent) & flag) must be true;
  3952.    for more than one matching extent with precisely the same endpoints,
  3953.    we choose the last extent in the extents_list.
  3954.    The search stops just before "before", if that is non-null.
  3955.    */
  3956.  
  3957. struct extent_at_arg
  3958. {
  3959.   EXTENT best_match;
  3960.   Memind best_start;
  3961.   Memind best_end;
  3962.   Lisp_Object prop;
  3963.   EXTENT before;
  3964. };
  3965.  
  3966. static int
  3967. extent_at_mapper (EXTENT e, void *arg)
  3968. {
  3969.   struct extent_at_arg *closure = (struct extent_at_arg *) arg;
  3970.  
  3971.   if (e == closure->before)
  3972.     return 1;
  3973.  
  3974.   /* If closure->prop is non-nil, then the extent is only acceptable
  3975.      if it has a non-nil value for that property. */
  3976.   if (!NILP (closure->prop))
  3977.     {
  3978.       Lisp_Object extent;
  3979.       XSETEXTENT (extent, e);
  3980.       if (NILP (Fextent_property (extent, closure->prop)))
  3981.     return 0;
  3982.     }
  3983.  
  3984.     {
  3985.       EXTENT current = closure->best_match;
  3986.  
  3987.       if (!current)
  3988.     goto accept;
  3989.       /* redundant but quick test */
  3990.       else if (extent_start (current) > extent_start (e))
  3991.     return 0;
  3992.  
  3993.       /* we return the "last" best fit, instead of the first --
  3994.      this is because then the glyph closest to two equivalent
  3995.      extents corresponds to the "extent-at" the text just past
  3996.      that same glyph */
  3997.       else if (!EXTENT_LESS_VALS (e, closure->best_start,
  3998.                   closure->best_end))
  3999.         goto accept;
  4000.       else
  4001.     return 0;
  4002.     accept:
  4003.       closure->best_match = e;
  4004.       closure->best_start = extent_start (e);
  4005.       closure->best_end = extent_end (e);
  4006.     }
  4007.  
  4008.   return 0;
  4009. }
  4010.  
  4011. DEFUN ("extent-at", Fextent_at, Sextent_at, 1, 4, 0,
  4012.        "Find \"smallest\" extent at POS in BUFFER having PROPERTY set.\n\
  4013. An extent is \"at\" POS if it overlaps the region (POS, POS+1); i.e. if\n\
  4014.  it covers the character after POS.  \"Smallest\" means the extent\n\
  4015.  that comes last in the display order; this normally means the extent\n\
  4016.  whose start position is closest to POS.  See `next-extent' for more\n\
  4017.  information.\n\
  4018. BUFFER defaults to the current buffer.\n\
  4019. PROPERTY defaults to nil, meaning that any extent will do.\n\
  4020. Properties are attached to extents with `set-extent-property', which see.\n\
  4021. Returns nil if POS is invalid or there is no matching extent at POS.\n\
  4022. If the fourth argument BEFORE is not nil, it must be an extent; any returned\n\
  4023.  extent will precede that extent.  This feature allows `extent-at' to be\n\
  4024.  used by a loop over extents.")
  4025.      (pos, buffer, property, before)
  4026.      Lisp_Object pos, buffer, property, before;
  4027. {
  4028.   Bytind position;
  4029.   Lisp_Object extent_obj = Qnil;
  4030.   EXTENT extent;
  4031.   struct buffer *buf;
  4032.   struct extent_at_arg closure;
  4033.  
  4034.   buf = decode_buffer (buffer, 0);
  4035.   XSETBUFFER (buffer, buf);
  4036.   position = get_bytind (buf, pos, GB_NO_ERROR_IF_BAD);
  4037.   CHECK_SYMBOL (property, 0);
  4038.   if (NILP (before))
  4039.     extent = 0;
  4040.   else
  4041.     extent = decode_extent (before, DE_MUST_BE_ATTACHED);
  4042.   if (extent && !EQ (buffer, extent_object (extent)))
  4043.     {
  4044.       XSETBUFFER (buffer, buf);
  4045.       signal_simple_error ("extent not in specified buffer", buffer);
  4046.     }
  4047.  
  4048.   /* it might be argued that invalid positions should cause
  4049.      errors, but the principle of least surprise dictates that
  4050.      nil should be returned (extent-at is often used in
  4051.      response to a mouse event, and in many cases previous events
  4052.      have changed the buffer contents). */
  4053.   if (!position || position == BI_BUF_Z (buf))
  4054.     return Qnil;
  4055.  
  4056.   closure.best_match = 0;
  4057.   closure.prop = property;
  4058.   closure.before = extent;
  4059.   
  4060.   map_extents_bytind (position, position+1, extent_at_mapper,
  4061.               (void *) &closure, make_buffer (buf), 0, ME_START_OPEN);
  4062.  
  4063.   if (!closure.best_match)
  4064.     return Qnil;
  4065.  
  4066.   XSETEXTENT (extent_obj, closure.best_match);
  4067.   return extent_obj;
  4068. }
  4069.  
  4070. /* ------------------------------- */
  4071. /*   verify_extent_modification()  */
  4072. /* ------------------------------- */
  4073.  
  4074. /* verify_extent_modification() is called when a buffer is modified to 
  4075.    check whether the modification is occuring inside a read-only extent.
  4076.  */
  4077.  
  4078. #ifdef ENERGIZE
  4079. extern int inside_parse_buffer; /* total kludge */
  4080. #endif
  4081.  
  4082. struct verify_extents_arg
  4083. {
  4084.   struct buffer *buf;
  4085.   Memind start;
  4086.   Memind end;
  4087. };
  4088.  
  4089. static int
  4090. verify_extent_mapper (EXTENT extent, void *arg)
  4091. {
  4092.   if (extent_read_only_p (extent))
  4093.     {
  4094.       struct verify_extents_arg *closure = (struct verify_extents_arg *) arg;
  4095.  
  4096.       /* Allow deletion if the extent is completely contained in
  4097.      the region being deleted.
  4098.      This is important for supporting tokens which are internally
  4099.      write-protected, but which can be killed and yanked as a whole.
  4100.      Ignore open/closed distinctions at this point.
  4101.      -- Rose
  4102.        */
  4103.       if (closure->start != closure->end &&
  4104.       extent_start (extent) >= closure->start &&
  4105.       extent_end (extent) <= closure->end)
  4106.     return 0;
  4107.  
  4108.       {
  4109.     Lisp_Object b;
  4110.     XSETBUFFER (b, closure->buf);
  4111.     while (1)
  4112.       Fsignal (Qbuffer_read_only, (list1 (b)));
  4113.       }
  4114.     }
  4115.  
  4116.   return 0;
  4117. }
  4118.  
  4119. void
  4120. verify_extent_modification (struct buffer *buf, Bytind from, Bytind to)
  4121. {
  4122.   int closed;
  4123.   struct verify_extents_arg closure;
  4124.  
  4125.   if (inside_undo
  4126. #ifdef ENERGIZE
  4127.       || inside_parse_buffer
  4128. #endif
  4129.       )
  4130.     return;
  4131.  
  4132.   /* If insertion, visit closed-endpoint extents touching the insertion
  4133.      point because the text would go inside those extents.  If deletion,
  4134.      treat the range as open on both ends so that touching extents are not
  4135.      visited.  Note that we assume that an insertion is occurring if the
  4136.      changed range has zero length, and a deletion otherwise.  This
  4137.      fails if a change (i.e. non-insertion, non-deletion) is happening.
  4138.      As far as I know, this doesn't currently occur in XEmacs. --ben */
  4139.   closed = (from==to);
  4140.   closure.buf = buf;
  4141.   closure.start = bytind_to_memind (buf, from);
  4142.   closure.end = bytind_to_memind (buf, to);
  4143.  
  4144.   map_extents_bytind (from, to, verify_extent_mapper, (void *) &closure,
  4145.               make_buffer (buf), 0,
  4146.               closed ? ME_END_CLOSED : ME_START_OPEN);
  4147. }
  4148.  
  4149. /* ------------------------------------ */
  4150. /*    process_extents_for_insertion()   */
  4151. /* ------------------------------------ */
  4152.  
  4153. struct process_extents_for_insertion_arg
  4154. {
  4155.   Bytind opoint;
  4156.   int length;
  4157.   struct buffer *buf;
  4158. };
  4159.    
  4160. /*   A region of length LENGTH was just inserted at OPOINT.  Modify all
  4161.      of the extents as required for the insertion, based on their
  4162.      start-open/end-open properties.
  4163.  */
  4164.  
  4165. static int
  4166. process_extents_for_insertion_mapper (EXTENT extent, void *arg)
  4167. {
  4168.   struct process_extents_for_insertion_arg *closure = 
  4169.     (struct process_extents_for_insertion_arg *) arg;
  4170.   struct buffer *buf = closure->buf;
  4171.   Memind index = bytind_to_memind (buf, closure->opoint);
  4172.  
  4173.   /* When this function is called, one end of the newly-inserted text should
  4174.      be adjacent to some endpoint of the extent, or disjoint from it.  If
  4175.      the insertion overlaps any existing extent, something is wrong.
  4176.    */
  4177. #ifdef ERROR_CHECK_EXTENTS
  4178.   if (extent_start (extent) > index &&
  4179.       extent_start (extent) < index + closure->length)
  4180.     abort ();
  4181.   if (extent_end (extent) > index &&
  4182.       extent_end (extent) < index + closure->length)
  4183.     abort ();
  4184. #endif
  4185.  
  4186.   /* The extent-adjustment code adjusted the extent's endpoints as if
  4187.      they were markers -- endpoints at the gap (i.e. the insertion
  4188.      point) go to the left of the insertion point, which is correct
  4189.      for [) extents.  We need to fix the other kinds of extents.
  4190.  
  4191.      Note that both conditions below will hold for zero-length (]
  4192.      extents at the gap.  Zero-length () extents would get adjusted
  4193.      such that their start is greater than their end; we treat them
  4194.      as [) extents.  This is unfortunately an inelegant part of the
  4195.      extent model, but there is no way around it. */
  4196.  
  4197.   {
  4198.     Memind new_start, new_end;
  4199.  
  4200.     new_start = extent_start (extent);
  4201.     new_end = extent_end (extent);
  4202.     if (index == extent_start (extent) && extent_start_open_p (extent) &&
  4203.     /* coerce zero-length () extents to [) */
  4204.     new_start != new_end)
  4205.       new_start += closure->length;
  4206.     if (index == extent_end (extent) && !extent_end_open_p (extent))
  4207.       new_end += closure->length;
  4208.     set_extent_endpoints_1 (extent, new_start, new_end);
  4209.   }
  4210.  
  4211.   return 0;
  4212. }
  4213.  
  4214. void
  4215. process_extents_for_insertion (struct buffer *buf, Bytind opoint, int length)
  4216. {
  4217.   struct process_extents_for_insertion_arg closure;
  4218.  
  4219.   closure.opoint = opoint;
  4220.   closure.length = length;
  4221.   closure.buf = buf;
  4222.   
  4223.   map_extents_bytind (opoint, opoint + length,
  4224.               process_extents_for_insertion_mapper,
  4225.               (void *) &closure, make_buffer (buf), 0,
  4226.               ME_END_CLOSED | ME_MIGHT_MODIFY_EXTENTS |
  4227.               ME_INCLUDE_INTERNAL);
  4228. }
  4229.  
  4230. /* ------------------------------------ */
  4231. /*    process_extents_for_deletion()    */
  4232. /* ------------------------------------ */
  4233.  
  4234. struct process_extents_for_deletion_arg
  4235. {
  4236.   Memind start, end;
  4237.   int destroy_included_extents;
  4238. };
  4239.  
  4240. /* This function is called when we're about to delete the range [from, to].
  4241.    Detach all of the extents that are completely inside the range [from, to],
  4242.    if they're detachable or open-open. */
  4243.  
  4244. static int
  4245. process_extents_for_deletion_mapper (EXTENT extent, void *arg)
  4246. {
  4247.   struct process_extents_for_deletion_arg *closure = 
  4248.     (struct process_extents_for_deletion_arg *) arg;
  4249.  
  4250.   /* If the extent lies completely within the range that
  4251.      is being deleted, then nuke the extent if it's detachable
  4252.      (otherwise, it will become a zero-length extent). */
  4253.  
  4254.   if (closure->start <= extent_start (extent) &&
  4255.       extent_end (extent) <= closure->end)
  4256.     {
  4257.       if (extent_detachable_p (extent))
  4258.     {
  4259.       if (closure->destroy_included_extents)
  4260.         destroy_extent (extent);
  4261.       else
  4262.         extent_detach (extent);
  4263.     }
  4264.     }
  4265.  
  4266.   return 0;
  4267. }
  4268.  
  4269. /* DESTROY_THEM means destroy the extents instead of just deleting them.
  4270.    It is unused currently, but perhaps might be used (there used to
  4271.    be a function process_extents_for_destruction(), #if 0'd out,
  4272.    that did the equivalent). */
  4273. void
  4274. process_extents_for_deletion (struct buffer *buf, Bytind from,
  4275.                   Bytind to, int destroy_them)
  4276. {
  4277.   struct process_extents_for_deletion_arg closure;
  4278.  
  4279.   closure.start = bytind_to_memind (buf, from);
  4280.   closure.end = bytind_to_memind (buf, to);
  4281.   closure.destroy_included_extents = destroy_them;
  4282.  
  4283.   map_extents_bytind (from, to, process_extents_for_deletion_mapper,
  4284.               (void *) &closure, make_buffer (buf), 0,
  4285.               ME_END_CLOSED | ME_MIGHT_MODIFY_EXTENTS);
  4286. }
  4287.  
  4288.  
  4289. /************************************************************************/
  4290. /*                extent properties                */
  4291. /************************************************************************/
  4292.  
  4293. /* return the value of PROPERTY in EXTENT's property list. */
  4294. Lisp_Object
  4295. extent_getf (EXTENT extent, Lisp_Object property)
  4296. {
  4297.   Lisp_Object tail = extent_plist (extent);
  4298.   Lisp_Object value;
  4299.  
  4300.   assert (SYMBOLP (property));
  4301.   return internal_getf (tail, property, &value) ? value : Qnil;
  4302. }
  4303.  
  4304. /* set the value of PROPERTY in EXTENT's property list to VALUE. */
  4305. void
  4306. extent_putf (EXTENT extent, Lisp_Object property, Lisp_Object value)
  4307. {
  4308.   Lisp_Object *location = extent_plist_addr (extent);
  4309.   assert (SYMBOLP (property));
  4310.  
  4311.   internal_putf (location, property, value);
  4312. }
  4313.  
  4314. void
  4315. set_extent_glyph (EXTENT extent, Lisp_Object glyph, int endp,
  4316.           unsigned int layout)
  4317. {
  4318.   extent = extent_ancestor (extent);
  4319.  
  4320.   if (!endp)
  4321.     {
  4322.       set_extent_begin_glyph (extent, glyph);
  4323.       extent_begin_glyph_layout (extent) = layout;
  4324.     }
  4325.   else
  4326.     {
  4327.       set_extent_end_glyph (extent, glyph);
  4328.       extent_end_glyph_layout (extent) = layout;
  4329.     }
  4330.  
  4331.   extent_changed_for_redisplay (extent, 1);
  4332. }
  4333.  
  4334. static Lisp_Object
  4335. glyph_layout_to_symbol (unsigned int layout)
  4336. {
  4337.   switch (layout)
  4338.     {
  4339.     case GL_TEXT: return Qtext;
  4340.     case GL_OUTSIDE_MARGIN: return Qoutside_margin;
  4341.     case GL_INSIDE_MARGIN: return Qinside_margin;
  4342.     case GL_WHITESPACE: return Qwhitespace;
  4343.     default: abort ();
  4344.     }
  4345.   return Qnil;    /* shut up compiler */
  4346. }
  4347.  
  4348. static unsigned int
  4349. symbol_to_glyph_layout (Lisp_Object layout_obj)
  4350. {
  4351.   unsigned int layout = 0;
  4352.  
  4353.   if (NILP (layout_obj))
  4354.     layout = GL_TEXT;
  4355.   else
  4356.     {
  4357.       CHECK_SYMBOL (layout_obj, 0);
  4358.       if (EQ (Qoutside_margin, layout_obj))
  4359.     layout = GL_OUTSIDE_MARGIN;
  4360.       else if (EQ (Qinside_margin, layout_obj))
  4361.     layout = GL_INSIDE_MARGIN;
  4362.       else if (EQ (Qwhitespace, layout_obj))
  4363.     layout = GL_WHITESPACE;
  4364.       else if (EQ (Qtext, layout_obj))
  4365.     layout = GL_TEXT;
  4366.       else
  4367.     signal_simple_error ("unknown glyph layout type", layout_obj);
  4368.     }
  4369.   return layout;
  4370. }
  4371.  
  4372. static Lisp_Object
  4373. set_extent_glyph_1 (Lisp_Object extent_obj, Lisp_Object glyph, int endp,
  4374.             Lisp_Object layout_obj)
  4375. {
  4376.   EXTENT extent = decode_extent (extent_obj, DE_MUST_HAVE_BUFFER);
  4377.   unsigned int layout = symbol_to_glyph_layout (layout_obj);
  4378.  
  4379.   /* Make sure we've actually been given a glyph or it's nil (meaning
  4380.      we're deleting a glyph from an extent. */
  4381.   if (!NILP (glyph))
  4382.     CHECK_GLYPH (glyph, 0);
  4383.  
  4384.   set_extent_glyph (extent, glyph, endp, layout);
  4385.   return glyph;
  4386. }
  4387.  
  4388. DEFUN ("set-extent-begin-glyph", Fset_extent_begin_glyph, 
  4389.        Sset_extent_begin_glyph, 2, 3, 0,
  4390.  "Display a bitmap, subwindow or string at the beginning of EXTENT.\n\
  4391. BEGIN-GLYPH must be a glyph object.  The layout policy defaults to `text'.")
  4392.   (extent, begin_glyph, layout)
  4393.    Lisp_Object extent, begin_glyph, layout;
  4394. {
  4395.   return set_extent_glyph_1 (extent, begin_glyph, 0, layout);
  4396. }
  4397.  
  4398. DEFUN ("set-extent-end-glyph", Fset_extent_end_glyph, 
  4399.        Sset_extent_end_glyph, 2, 3, 0,
  4400.  "Display a bitmap, subwindow or string at the end of the EXTENT.\n\
  4401. END-GLYPH must be a glyph object.  The layout policy defaults to `text'.")
  4402.   (extent, end_glyph, layout)
  4403.    Lisp_Object extent, end_glyph, layout;
  4404. {
  4405.   return set_extent_glyph_1 (extent, end_glyph, 1, layout);
  4406. }
  4407.  
  4408. DEFUN ("extent-begin-glyph", Fextent_begin_glyph, Sextent_begin_glyph, 1, 1, 0,
  4409.   "Return the glyph object displayed at the beginning of EXTENT.\n\
  4410. If there is none, nil is returned.")
  4411.      (extent_obj)
  4412.      Lisp_Object extent_obj;
  4413. {
  4414.   return extent_begin_glyph (decode_extent (extent_obj, 0));
  4415. }
  4416.  
  4417. DEFUN ("extent-end-glyph", Fextent_end_glyph, Sextent_end_glyph, 1, 1, 0,
  4418.   "Return the glyph object displayed at the end of EXTENT.\n\
  4419. If there is none, nil is returned.")
  4420.      (extent_obj)
  4421.      Lisp_Object extent_obj;
  4422. {
  4423.   return extent_end_glyph (decode_extent (extent_obj, 0));
  4424. }
  4425.  
  4426. DEFUN ("set-extent-begin-glyph-layout", Fset_extent_begin_glyph_layout,
  4427.        Sset_extent_begin_glyph_layout, 2, 2, 0,
  4428.   "Set the layout policy of the given extent's begin glyph.\n\
  4429. Access this using the `extent-begin-glyph-layout' function.")
  4430.     (extent, layout)
  4431.     Lisp_Object extent, layout;
  4432. {
  4433.   EXTENT e = decode_extent (extent, 0);
  4434.   e = extent_ancestor (e);
  4435.   extent_begin_glyph_layout (e) = symbol_to_glyph_layout (layout);
  4436.   extent_maybe_changed_for_redisplay (e, 1);
  4437.   return layout;
  4438. }
  4439.  
  4440. DEFUN ("set-extent-end-glyph-layout", Fset_extent_end_glyph_layout,
  4441.        Sset_extent_end_glyph_layout, 2, 2, 0,
  4442.   "Set the layout policy of the given extent's end glyph.\n\
  4443. Access this using the `extent-end-glyph-layout' function.")
  4444.     (extent, layout)
  4445.     Lisp_Object extent, layout;
  4446. {
  4447.   EXTENT e = decode_extent (extent, 0);
  4448.   e = extent_ancestor (e);
  4449.   extent_end_glyph_layout (e) = symbol_to_glyph_layout (layout);
  4450.   extent_maybe_changed_for_redisplay (e, 1);
  4451.   return layout;
  4452. }
  4453.  
  4454. DEFUN ("extent-begin-glyph-layout", Fextent_begin_glyph_layout,
  4455.        Sextent_begin_glyph_layout, 1, 1, 0,
  4456.   "Return the layout policy associated with the given extent's begin glyph.\n\
  4457. Set this using the `set-extent-begin-glyph-layout' function.")
  4458.     (extent)
  4459.     Lisp_Object extent;
  4460. {
  4461.   EXTENT e = decode_extent (extent, 0);
  4462.   return glyph_layout_to_symbol (extent_begin_glyph_layout (e));
  4463. }
  4464.  
  4465. DEFUN ("extent-end-glyph-layout", Fextent_end_glyph_layout,
  4466.        Sextent_end_glyph_layout, 1, 1, 0,
  4467.   "Return the layout policy associated with the given extent's end glyph.\n\
  4468. Set this using the `set-extent-end-glyph-layout' function.")
  4469.     (extent)
  4470.     Lisp_Object extent;
  4471. {
  4472.   EXTENT e = decode_extent (extent, 0);
  4473.   return glyph_layout_to_symbol (extent_end_glyph_layout (e));
  4474. }
  4475.  
  4476. DEFUN ("set-extent-priority", Fset_extent_priority, Sset_extent_priority,
  4477.        2, 2, 0,
  4478.   "Changes the display priority of EXTENT.\n\
  4479. When the extent attributes are being merged for display, the priority\n\
  4480. is used to determine which extent takes precedence in the event of a\n\
  4481. conflict (two extents whose faces both specify font, for example: the\n\
  4482. font of the extent with the higher priority will be used).\n\
  4483. Extents are created with priority 0; priorities may be negative.")
  4484.     (extent, pri)
  4485.     Lisp_Object extent, pri;
  4486. {
  4487.   EXTENT e = decode_extent (extent, 0);
  4488.  
  4489.   CHECK_INT (pri, 0);
  4490.   e = extent_ancestor (e);
  4491.   set_extent_priority (e, XINT (pri));
  4492.   extent_maybe_changed_for_redisplay (e, 1);
  4493.   return pri;
  4494. }
  4495.  
  4496. DEFUN ("extent-priority", Fextent_priority, Sextent_priority, 1, 1, 0,
  4497.   "Return the display priority of EXTENT; see `set-extent-priority'.")
  4498.      (extent)
  4499.      Lisp_Object extent;
  4500. {
  4501.   EXTENT e = decode_extent (extent, 0);
  4502.   return make_number (extent_priority (e));
  4503. }
  4504.  
  4505. DEFUN ("set-extent-property", Fset_extent_property, Sset_extent_property,
  4506.        3, 3, 0,
  4507.   "Change a property of an extent.\n\
  4508. PROPERTY may be any symbol; the value stored may be accessed with\n\
  4509.  the `extent-property' function.\n\
  4510. The following symbols have predefined meanings:\n\
  4511. \n\
  4512.  detached    Removes the extent from its buffer; setting this is the same\n\
  4513.         as calling `detach-extent'.\n\
  4514. \n\
  4515.  destroyed    Removes the extent from its buffer, and makes it unusable in\n\
  4516.         the future; this is the same calling `delete-extent'.\n\
  4517. \n\
  4518.  priority    Change redisplay priority; same as `set-extent-priority'.\n\
  4519. \n\
  4520.  start-open    Whether the set of characters within the extent is treated\n\
  4521.         being open on the left, that is, whether the start position\n\
  4522.         is an exclusive, rather than inclusive, boundary.  If true,\n\
  4523.         then characters inserted exactly at the beginning of the\n\
  4524.         extent will remain outside of the extent; otherwise they\n\
  4525.         will go into the extent, extending it.\n\
  4526. \n\
  4527.  end-open    Whether the set of characters within the extent is treated\n\
  4528.         being open on the right, that is, whether the end position\n\
  4529.         is an exclusive, rather than inclusive, boundary.  If true,\n\
  4530.         then characters inserted exactly at the end of the extent\n\
  4531.         will remain outside of the extent; otherwise they will go\n\
  4532.         into the extent, extending it.\n\
  4533. \n\
  4534.         By default, extents have the `end-open' but not the\n\
  4535.         `start-open' property set.\n\
  4536. \n\
  4537.  read-only    Text within this extent will be unmodifiable.\n\
  4538. \n\
  4539.  detachable    Whether the extent gets detached (as with `detach-extent')\n\
  4540.                 when all the text within the extent is deleted.  This\n\
  4541.         is true by default.  If this property is not set, the\n\
  4542.         extent becomes a zero-length extent when its text is\n\
  4543.         deleted. (In such a case, the `start-open' property is\n\
  4544.         automatically removed if both the `start-open' and\n\
  4545.         `end-open' properties are set, since zero-length extents\n\
  4546.         open on both ends are not allowed.)\n\
  4547. \n\
  4548.  face        The face in which to display the text.  Setting this is the\n\
  4549.         same as calling `set-extent-face'.\n\
  4550. \n\
  4551.  highlight    Highlight the extent when the mouse moves over it.\n\
  4552. \n\
  4553.  duplicable    Whether this extent should be copied into strings, so that\n\
  4554.         kill, yank, and undo commands will restore or copy it.\n\
  4555. \n\
  4556.  unique        Meaningful only in conjunction with `duplicable'.  When this\n\
  4557.         is set, there may be only one instance of this extent\n\
  4558.         attached at a time: if it is copied to the kill ring and\n\
  4559.         then yanked, the extent is not copied.  If, however, it is\n\
  4560.         killed (removed from the buffer) and then yanked, it will\n\
  4561.         be re-attached at the new position.\n\
  4562. \n\
  4563.  invisible    Text under this extent is treated as not present for the\n\
  4564.          purpose of redisplay.  The text is still visible to other\n\
  4565.         functions that examine a buffer's text, however.\n\
  4566. \n\
  4567.  intangible    (not yet implemented) Text under this extent is treated as\n\
  4568.                 not present.  Neither redisplay nor any other functions that\n\
  4569.         examine a buffer's text will see the text under this extent.\n\
  4570. \n\
  4571.  keymap        This keymap is consulted for mouse clicks on this extent, or\n\
  4572.         keypresses made while point is within the extent.\n\
  4573. \n\
  4574.  copy-function    This is a hook that is run when a duplicable extent is about\n\
  4575.         to be copied from a buffer to a string (or the kill ring).\n\
  4576.         It is called with three arguments, the extent, and the\n\
  4577.         buffer-positions within it which are being copied.  If this\n\
  4578.         function returns nil, then the extent will not be copied;\n\
  4579.         otherwise it will.\n\
  4580. \n\
  4581.  paste-function This is a hook that is run when a duplicable extent is\n\
  4582.         about to be copied from a string (or the kill ring) into a\n\
  4583.         buffer.  It is called with three arguments, the original\n\
  4584.         extent, and the buffer positions which the copied extent\n\
  4585.         will occupy.  (This hook is run after the corresponding text\n\
  4586.         has already been inserted into the buffer.)  Note that the\n\
  4587.         extent argument may be detached when this function is run.\n\
  4588.         If this function returns nil, no extent will be inserted.\n\
  4589.         Otherwise, there will be an extent covering the range in\n\
  4590.         question.\n\
  4591. \n\
  4592.         If the original extent is not attached to a buffer, then it\n\
  4593.         will be re-attached at this range.  Otherwise, a copy will\n\
  4594.         be made, and that copy attached here.\n\
  4595. \n\
  4596.         The copy-function and paste-function are meaningful only for\n\
  4597.         extents with the `duplicable' flag set, and if they are not\n\
  4598.         specified, behave as if `t' was the returned value.  When\n\
  4599.         these hooks are invoked, the current buffer is the buffer\n\
  4600.         which the extent is being copied from/to, respectively.")
  4601.      (extent, property, value)
  4602.      Lisp_Object extent, property, value;
  4603. {
  4604.   /* This function can GC if property is `keymap' */
  4605.   EXTENT e = decode_extent (extent, 0);
  4606.   CHECK_SYMBOL (property, 0);
  4607.  
  4608.   if (EQ (property, Qread_only))
  4609.     extent_read_only_p (e) = !NILP (value);
  4610.   else if (EQ (property, Qhighlight))
  4611.     extent_highlight_p (e) = !NILP (value);
  4612.   else if (EQ (property, Qunique))
  4613.     extent_unique_p (e) = !NILP (value);
  4614.   else if (EQ (property, Qduplicable))
  4615.     extent_duplicable_p (e) = !NILP (value);
  4616.   else if (EQ (property, Qinvisible))
  4617.     {
  4618.       set_extent_invisible (e, !NILP (value));
  4619.     }
  4620.   else if (EQ (property, Qintangible))
  4621.     {
  4622.       set_extent_intangible (e, !NILP (value));
  4623.     }
  4624.   else if (EQ (property, Qdetachable))
  4625.     extent_detachable_p (e) = !NILP (value);
  4626.  
  4627.   else if (EQ (property, Qdetached))
  4628.     {
  4629.       if (NILP (value)) error ("can only set `detached' to t");
  4630.       Fdetach_extent (extent);
  4631.     }
  4632.   else if (EQ (property, Qdestroyed))
  4633.     {
  4634.       if (NILP (value)) error ("can only set `destroyed' to t");
  4635.       Fdelete_extent (extent);
  4636.     }
  4637.   else if (EQ (property, Qpriority))
  4638.     {
  4639.       Fset_extent_priority (extent, value);
  4640.     }
  4641.   else if (EQ (property, Qface))
  4642.     {
  4643.       Fset_extent_face (extent, value);
  4644.     }
  4645.   else if (EQ (property, Qbegin_glyph_layout))
  4646.     {
  4647.       Fset_extent_begin_glyph_layout (extent, value);
  4648.     }
  4649.   else if (EQ (property, Qend_glyph_layout))
  4650.     {
  4651.       Fset_extent_end_glyph_layout (extent, value);
  4652.     }
  4653.   /* For backwards compatibility.  We use begin glyph because it is by
  4654.      far the more used of the two. */
  4655.   else if (EQ (property, Qglyph_layout))
  4656.     {
  4657.       Fset_extent_begin_glyph_layout (extent, value);
  4658.     }
  4659.  
  4660.   else if (EQ (property, Qbegin_glyph))
  4661.     Fset_extent_begin_glyph (extent, value, Qnil);
  4662.  
  4663.   else if (EQ (property, Qend_glyph))
  4664.     Fset_extent_end_glyph (extent, value, Qnil);
  4665.  
  4666.   else if (EQ (property, Qstart_open) ||
  4667.        EQ (property, Qend_open) ||
  4668.        EQ (property, Qstart_closed) ||
  4669.        EQ (property, Qend_closed))
  4670.     {
  4671.       int start_open = -1, end_open = -1;
  4672.       if (EQ (property, Qstart_open))
  4673.     start_open = !NILP (value);
  4674.       else if (EQ (property, Qend_open))
  4675.     end_open = !NILP (value);
  4676.       /* Support (but don't document...) the obvious antonyms. */
  4677.       else if (EQ (property, Qstart_closed))
  4678.     start_open = NILP (value);
  4679.       else
  4680.     end_open = NILP (value);
  4681.       set_extent_openness (e, start_open, end_open);
  4682.     }
  4683.   else
  4684.     {
  4685. #ifdef ENERGIZE
  4686.       if (EQ (property, Qenergize))
  4687.     error ("Thou shalt not change the `energize' extent property");
  4688. #endif
  4689.  
  4690.       if (EQ (property, Qkeymap))
  4691.     while (NILP (Fkeymapp (value)))
  4692.       value = wrong_type_argument (Qkeymapp, value);
  4693.  
  4694.       extent_putf (e, property, value);
  4695.     }
  4696.  
  4697.   return value;
  4698. }
  4699.  
  4700. DEFUN ("extent-property", Fextent_property, Sextent_property, 2, 2, 0,
  4701.  "Return EXTENT's value for property PROPERTY.\n\
  4702. See `set-extent-property' for the built-in property names.")
  4703.   (extent, property)
  4704.    Lisp_Object extent, property;
  4705. {
  4706.   EXTENT e = decode_extent (extent, 0);
  4707.   CHECK_SYMBOL (property, 0);
  4708.  
  4709.   if      (EQ (property, Qdetached))
  4710.     return (extent_detached_p (e) ? Qt : Qnil);
  4711.   else if (EQ (property, Qdestroyed))
  4712.     return (!EXTENT_LIVE_P (e) ? Qt : Qnil);
  4713. #define RETURN_FLAG(flag) \
  4714.   return (extent_normal_field (e, flag) ? Qt : Qnil)
  4715.   else if (EQ (property, Qstart_open))     RETURN_FLAG (start_open);
  4716.   else if (EQ (property, Qend_open))     RETURN_FLAG (end_open);
  4717.   else if (EQ (property, Qread_only))     RETURN_FLAG (read_only);
  4718.   else if (EQ (property, Qhighlight))     RETURN_FLAG (highlight);
  4719.   else if (EQ (property, Qunique))     RETURN_FLAG (unique);
  4720.   else if (EQ (property, Qduplicable))     RETURN_FLAG (duplicable);
  4721.   else if (EQ (property, Qinvisible))     RETURN_FLAG (invisible);
  4722.   else if (EQ (property, Qintangible))     RETURN_FLAG (intangible);
  4723.   else if (EQ (property, Qdetachable))     RETURN_FLAG (detachable);
  4724. #undef RETURN_FLAG
  4725.   /* Support (but don't document...) the obvious antonyms. */
  4726.   else if (EQ (property, Qstart_closed))
  4727.     return (extent_start_open_p (e) ? Qnil : Qt);
  4728.   else if (EQ (property, Qend_closed))
  4729.     return (extent_end_open_p (e) ? Qnil : Qt);
  4730.   else if (EQ (property, Qpriority))
  4731.     return make_number (extent_priority (e));
  4732.   else if (EQ (property, Qface))
  4733.     return Fextent_face (extent);
  4734.   else if (EQ (property, Qbegin_glyph_layout))
  4735.     return Fextent_begin_glyph_layout (extent);
  4736.   else if (EQ (property, Qend_glyph_layout))
  4737.     return Fextent_end_glyph_layout (extent);
  4738.   /* For backwards compatibility.  We use begin glyph because it is by
  4739.      far the more used of the two. */
  4740.   else if (EQ (property, Qglyph_layout))
  4741.     return Fextent_begin_glyph_layout (extent);
  4742.   else if (EQ (property, Qbegin_glyph))
  4743.     return extent_begin_glyph (e);
  4744.   else if (EQ (property, Qend_glyph))
  4745.     return extent_end_glyph (e);
  4746.   else
  4747.     return extent_getf (e, property);
  4748. }
  4749.  
  4750. DEFUN ("extent-properties", Fextent_properties, Sextent_properties, 1, 1, 0,
  4751.  "Return a property list of the attributes of the given extent.\n\
  4752. Do not modify this list; use `set-extent-property' instead.")
  4753.   (extent)
  4754.    Lisp_Object extent;
  4755. {
  4756.   EXTENT e, anc;
  4757.   Lisp_Object result, face, anc_obj = Qnil;
  4758.  
  4759.   CHECK_EXTENT (extent, 0);
  4760.   e = XEXTENT (extent);
  4761.   if (!EXTENT_LIVE_P (e))
  4762.     return Fcons (Qdestroyed, Fcons (Qt, Qnil));
  4763.  
  4764.   anc = extent_ancestor (e);
  4765.   XSETEXTENT (anc_obj, anc);
  4766.  
  4767.   /* For efficiency, use the ancestor for all properties except detached */
  4768.  
  4769.   result = extent_plist (anc);
  4770.   face = Fextent_face (anc_obj);
  4771.   if (!NILP (face))
  4772.     result = Fcons (Qface, Fcons (face, result));
  4773.  
  4774.   /* For now continue to include this for backwards compatibility. */
  4775.   if (extent_begin_glyph_layout (anc) != GL_TEXT)
  4776.     result = Fcons (Qglyph_layout,
  4777.             glyph_layout_to_symbol (extent_begin_glyph_layout (anc)));
  4778.  
  4779.   if (extent_begin_glyph_layout (anc) != GL_TEXT)
  4780.     result = Fcons (Qbegin_glyph_layout,
  4781.             glyph_layout_to_symbol (extent_begin_glyph_layout (anc)));
  4782.   if (extent_end_glyph_layout (anc) != GL_TEXT)
  4783.     result = Fcons (Qend_glyph_layout,
  4784.             glyph_layout_to_symbol (extent_end_glyph_layout (anc)));
  4785.  
  4786.   if (!NILP (extent_end_glyph (anc)))
  4787.     result = Fcons (Qend_glyph, Fcons (extent_end_glyph (anc), result));
  4788.   if (!NILP (extent_begin_glyph (anc)))
  4789.     result = Fcons (Qbegin_glyph, Fcons (extent_begin_glyph (anc), result));
  4790.  
  4791.   if (extent_priority (anc) != 0)
  4792.     result = Fcons (Qpriority, Fcons (make_number (extent_priority (anc)),
  4793.                       result));
  4794.  
  4795. #define CONS_FLAG(flag, sym) if (extent_normal_field (anc, flag)) \
  4796.   result = Fcons (sym, Fcons (Qt, result))
  4797.   CONS_FLAG (end_open, Qend_open);
  4798.   CONS_FLAG (start_open, Qstart_open);
  4799.   CONS_FLAG (invisible, Qinvisible);
  4800.   CONS_FLAG (intangible, Qintangible);
  4801.   CONS_FLAG (detachable, Qdetachable);
  4802.   CONS_FLAG (duplicable, Qduplicable);
  4803.   CONS_FLAG (unique, Qunique);
  4804.   CONS_FLAG (highlight, Qhighlight);
  4805.   CONS_FLAG (read_only, Qread_only);
  4806. #undef CONS_FLAG
  4807.  
  4808.   /* detached is not an inherited property */
  4809.   if (extent_detached_p (e))
  4810.     result = Fcons (Qdetached, Fcons (Qt, result));
  4811.  
  4812.   return result;
  4813. }
  4814.  
  4815.  
  4816. /************************************************************************/
  4817. /*                     highlighting                      */
  4818. /************************************************************************/
  4819.  
  4820. /* The display code looks into the Vlast_highlighted_extent variable to 
  4821.    correctly display highlighted extents.  This updates that variable,
  4822.    and marks the appropriate buffers as needing some redisplay.
  4823.  */
  4824. static void
  4825. do_highlight (Lisp_Object extent_obj, int highlight_p)
  4826. {
  4827.   if (( highlight_p && (EQ (Vlast_highlighted_extent, extent_obj))) ||
  4828.       (!highlight_p && (EQ (Vlast_highlighted_extent, Qnil))))
  4829.     return;
  4830.   if (EXTENTP (Vlast_highlighted_extent) &&
  4831.       EXTENT_LIVE_P (XEXTENT (Vlast_highlighted_extent)))
  4832.     {
  4833.       /* do not recurse on descendants.  Only one extent is highlighted
  4834.      at a time. */
  4835.       extent_changed_for_redisplay (XEXTENT (Vlast_highlighted_extent), 0);
  4836.     }
  4837.   Vlast_highlighted_extent = Qnil;
  4838.   if (!NILP (extent_obj)
  4839.       && BUFFERP (extent_object (XEXTENT (extent_obj)))
  4840.       && highlight_p)
  4841.     {
  4842.       extent_changed_for_redisplay (XEXTENT (extent_obj), 0);
  4843.       Vlast_highlighted_extent = extent_obj;
  4844.     }
  4845. }
  4846.  
  4847. DEFUN ("force-highlight-extent", Fforce_highlight_extent, 
  4848.        Sforce_highlight_extent, 1, 2, 0,
  4849.  "Highlight or unhighlight the given extent.\n\
  4850. If the second arg is non-nil, it will be highlighted, else dehighlighted.\n\
  4851. This is the same as `highlight-extent', except that it will work even\n\
  4852. on extents without the 'highlight property.")
  4853.      (extent_obj, highlight_p)
  4854.      Lisp_Object extent_obj, highlight_p;
  4855. {
  4856.   if (NILP (extent_obj))
  4857.     highlight_p = Qnil;
  4858.   else
  4859.     XSETEXTENT (extent_obj, decode_extent (extent_obj, DE_MUST_BE_ATTACHED));
  4860.   do_highlight (extent_obj, !NILP (highlight_p));
  4861.   return Qnil;
  4862. }
  4863.  
  4864. DEFUN ("highlight-extent", Fhighlight_extent, Shighlight_extent, 1, 2, 0,
  4865.  "Highlight the given extent, if it is highlightable\n(\
  4866. that is, if it has the 'highlight property).\n\
  4867. If the second arg is non-nil, it will be highlighted, else dehighlighted.\n\
  4868. Highlighted extents are displayed as if they were merged with the 'highlight\n\
  4869. face.")
  4870.      (extent_obj, highlight_p)
  4871.      Lisp_Object extent_obj, highlight_p;
  4872. {
  4873.   if (EXTENTP (extent_obj) && !extent_highlight_p (XEXTENT (extent_obj)))
  4874.     return Qnil;
  4875.   else
  4876.     return (Fforce_highlight_extent (extent_obj, highlight_p));
  4877. }
  4878.  
  4879.  
  4880. /************************************************************************/
  4881. /*                extent replicas                */
  4882. /************************************************************************/
  4883.  
  4884. /* #### All of this shit needs to be reviewed.  I personally think that
  4885.    extent replicas should be trashed and extents should just be extended
  4886.    so they work over strings as well as buffers. --ben */
  4887.  
  4888. /* copy/paste hooks */
  4889.  
  4890. static int
  4891. run_extent_copy_paste_internal (EXTENT e, Bufpos from, Bufpos to,
  4892.                 Lisp_Object buffer,
  4893.                 Lisp_Object prop)
  4894. {
  4895.   /* This function can GC */
  4896.   Lisp_Object extent;
  4897.   Lisp_Object copy_fn;
  4898.   XSETEXTENT (extent, e);
  4899.   copy_fn = Fextent_property (extent, prop);
  4900.   if (!NILP (copy_fn))
  4901.     {
  4902.       Lisp_Object flag;
  4903.       struct gcpro gcpro1, gcpro2, gcpro3;
  4904.       GCPRO3 (extent, copy_fn, buffer);
  4905.       flag = call3_in_buffer (XBUFFER (buffer), copy_fn, extent,
  4906.                   make_number (from), make_number (to));
  4907.       UNGCPRO;
  4908.       if (NILP (flag) || !EXTENT_LIVE_P (XEXTENT (extent)))
  4909.     return 0;
  4910.     }
  4911.   return 1;
  4912. }
  4913.  
  4914. static int
  4915. run_extent_copy_function_bufpos (EXTENT e, Bufpos from, Bufpos to)
  4916. {
  4917.   /* This function can GC */
  4918.   return run_extent_copy_paste_internal (e, from, to, extent_object (e),
  4919.                      Qcopy_function);
  4920. }
  4921.  
  4922. static int
  4923. run_extent_paste_function (EXTENT e, Bytind from, Bytind to,
  4924.                struct buffer *buf)
  4925. {
  4926.   /* This function can GC */
  4927.   return run_extent_copy_paste_internal (e, bytind_to_bufpos (buf, from),
  4928.                      bytind_to_bufpos (buf, to),
  4929.                      make_buffer (buf),
  4930.                      Qpaste_function);
  4931. }
  4932.  
  4933. static void   
  4934. update_extent (EXTENT extent, Bytind from, Bytind to)
  4935. {
  4936.   set_extent_endpoints (extent, from, to);
  4937. #ifdef ENERGIZE
  4938.   restore_energize_extent_state (extent);
  4939. #endif
  4940. }
  4941.  
  4942. /* Insert an extent, usually from the dup_list of a string which
  4943.    has just been inserted.
  4944.    This code does not handle the case of undo.
  4945.    */
  4946. static Lisp_Object
  4947. insert_extent (EXTENT extent, Bytind new_start, Bytind new_end,
  4948.            struct buffer *buf, int run_hooks)
  4949. {
  4950.   /* This function can GC */
  4951.   Lisp_Object tmp;
  4952.  
  4953.   if (!BUFFERP (extent_object (extent)))
  4954.     goto copy_it;
  4955.   if (XBUFFER (extent_object (extent)) != buf)
  4956.     goto copy_it;
  4957.  
  4958.   if (extent_detached_p (extent))
  4959.     {
  4960.       if (run_hooks &&
  4961.       !run_extent_paste_function (extent, new_start, new_end, buf))
  4962.     /* The paste-function said don't re-attach this extent here. */
  4963.     return Qnil;
  4964.       else
  4965.     update_extent (extent, new_start, new_end);
  4966.     }
  4967.   else
  4968.     {
  4969.       Bytind exstart = extent_endpoint_bytind (extent, 0);
  4970.       Bytind exend = extent_endpoint_bytind (extent, 1);
  4971.       
  4972.       if (exend < new_start || exstart > new_end)
  4973.     goto copy_it;
  4974.       else
  4975.     {
  4976.       new_start = min (exstart, new_start);
  4977.       new_end = max (exend, new_end);
  4978.       if (exstart != new_start || exend != new_end)
  4979.         update_extent (extent, new_start, new_end);
  4980.     }
  4981.     }
  4982.  
  4983.   XSETEXTENT (tmp, extent);
  4984.   return tmp;
  4985.  
  4986.  copy_it:
  4987.   if (run_hooks &&
  4988.       !run_extent_paste_function (extent, new_start, new_end, buf))
  4989.     /* The paste-function said don't attach a copy of the extent here. */
  4990.     return Qnil;
  4991.   else
  4992.     {
  4993.       XSETEXTENT (tmp, copy_extent (extent, new_start, new_end,
  4994.                     make_buffer (buf)));
  4995.       return tmp;
  4996.     }
  4997. }
  4998.  
  4999. DEFUN ("insert-extent", Finsert_extent, Sinsert_extent, 1, 4, 0,
  5000.  "Insert EXTENT from START to END in the current buffer.\n\
  5001. This operation does not insert any characters,\n\
  5002. but otherwise acts like `insert' of a string whose\n\
  5003. string-extent-data calls for EXTENT to be inserted.\n\
  5004. Returns the newly-inserted extent.\n\
  5005. The fourth arg, NO-HOOKS, can be used to inhibit the running of the\n\
  5006.  extent's `paste-function' property if it has one.\n\
  5007. See documentation on `detach-extent' for a discussion of undo recording.")
  5008.   (extent, start, end, no_hooks)
  5009.    Lisp_Object extent, start, end, no_hooks;
  5010. {
  5011.   EXTENT ext = decode_extent (extent, 0);
  5012.   Lisp_Object copy;
  5013.   Bytind s, e;
  5014.  
  5015.   get_bufrange_bytind (current_buffer, start, end, &s, &e,
  5016.                GB_ALLOW_PAST_ACCESSIBLE);
  5017.  
  5018.   copy = insert_extent (ext, s, e, current_buffer, NILP (no_hooks));
  5019.   if (EXTENTP (copy))
  5020.     {
  5021.       if (extent_duplicable_p (XEXTENT (copy)))
  5022.     record_extent (copy, 1);
  5023.     }
  5024.   return copy;
  5025. }
  5026.  
  5027. /* ####  A lot of this stuff is going to change, don't use it yet  -- jwz */
  5028.  
  5029. DEFUN ("string-extent-data", Fstring_extent_data, Sstring_extent_data, 1, 1, 0,
  5030.  "Return the saved extent data associated with the given string.\n\
  5031. \n\
  5032.   NOTE: this function may go away in the future, in favor of making\n\
  5033.   `map-extents' accept a string as an argument.\n\
  5034. \n\
  5035. The format is a list of extent-replica objects, each with an extent\n\
  5036. and start and end positions within the string itself.\n\
  5037. Set this using the `set-string-extent-data' function.\n\
  5038. \n\
  5039. The `concat' function logically concatenates this list, reconstructing\n\
  5040. the extent information with adjusted start and end positions.\n\
  5041. \n\
  5042. When `buffer-substring' or a similar function creates a string,\n\
  5043. it stores an entry on this list for every `duplicable' extent overlapping\n\
  5044. the string.  See `set-extent-property'.\n\
  5045. \n\
  5046. When `insert' or a similar function inserts the string into a buffer,\n\
  5047. each saved extent is copied into the buffer.  If the saved extent is\n\
  5048. already in the buffer at an adjacent location, it is extended.  If the\n\
  5049. saved extent is detached from the buffer, it is reattached.  If the saved\n\
  5050. extent is already attached, or is detached from a different buffer, it is\n\
  5051. copied as if by `copy-extent', and the extent's `paste-function' is\n\
  5052. consulted.  This entire sequence of events is also available in the\n\
  5053. function `insert-extent'.")
  5054.     (string)
  5055.     Lisp_Object string;
  5056. {
  5057.   CHECK_STRING (string, 0);
  5058.   return string_dups (XSTRING (string));
  5059. }
  5060.  
  5061. DEFUN ("set-string-extent-data", Fset_string_extent_data,
  5062.        Sset_string_extent_data, 2, 2, 0,
  5063.  "Set the saved extent data associated with the given string.\n\
  5064. Access this using the `string-extent-data' function.")
  5065.     (string, data)
  5066.     Lisp_Object string, data;
  5067. {
  5068.   CHECK_STRING (string, 0);
  5069.   CHECK_LIST (data, 1);
  5070.   CHECK_IMPURE (string);
  5071.   
  5072.   set_string_dups (XSTRING (string), data);
  5073.   return string;
  5074. }
  5075.  
  5076. static EXTENT_REPLICA
  5077. decode_extent_replica (Lisp_Object obj)
  5078. {
  5079.   CHECK_LIVE_EXTENT_REPLICA (obj, 0);
  5080.   return XEXTENT_REPLICA (obj);
  5081. }
  5082.  
  5083. /* Extent replica goo.
  5084.    This is a read-only data structure.
  5085.    As far as the Lisp programmer is concerned, it is used ONLY as a carrier for
  5086.    string-extent-data information.
  5087.    */
  5088. DEFUN ("make-extent-replica", Fmake_extent_replica, Smake_extent_replica,
  5089.        3, 3, 0,
  5090.  "Make an object suitable for use with `set-string-extent-data'.\n\
  5091. The arguments are EXTENT, START, and END.\n\
  5092. There are no mutator functions for this data structure, only accessors.")
  5093.     (extent, start, end)
  5094.     Lisp_Object extent, start, end;
  5095. {
  5096.   EXTENT_REPLICA dup;
  5097.   Lisp_Object res;
  5098.  
  5099.   CHECK_LIVE_EXTENT (extent, 0);
  5100.   CHECK_INT_COERCE_MARKER (start, 1);
  5101.   CHECK_INT_COERCE_MARKER (end, 2);
  5102.  
  5103.   dup = make_extent_replica (extent, XINT (start), XINT (end));
  5104.   XSETEXTENT_REPLICA (res, dup);
  5105.   return res;
  5106. }
  5107.  
  5108. DEFUN ("extent-replica-p", Fextent_replica_p, Sextent_replica_p, 1, 1, 0,
  5109.   "T if OBJECT is an extent replica.")
  5110.   (object)
  5111.      Lisp_Object object;
  5112. {
  5113.   if (EXTENT_REPLICAP (object))
  5114.     return Qt;
  5115.   return Qnil;
  5116. }
  5117.  
  5118. DEFUN ("extent-replica-live-p", Fextent_replica_live_p, Sextent_replica_live_p,
  5119.        1, 1, 0,
  5120.   "T if OBJECT is an extent replica that has not been destroyed.")
  5121.   (object)
  5122.      Lisp_Object object;
  5123. {
  5124.   if (EXTENT_REPLICA_LIVE_P (XEXTENT_REPLICA (object)))
  5125.     return Qt;
  5126.   return Qnil;
  5127. }
  5128.  
  5129. DEFUN ("extent-replica-extent", Fextent_replica_extent, Sextent_replica_extent,
  5130.        1, 1, 0,
  5131.  "Return the extent of the specified extent replica.\n\
  5132. See `make-extent-replica'.")
  5133.      (extent_replica)
  5134.      Lisp_Object extent_replica;
  5135. {
  5136.   return extent_replica_extent (decode_extent_replica (extent_replica));
  5137. }
  5138.  
  5139. DEFUN ("extent-replica-start", Fextent_replica_start, Sextent_replica_start,
  5140.        1, 1, 0,
  5141.  "Return the start of the specified extent replica.\n\
  5142. See `make-extent-replica'.")
  5143.      (extent_replica)
  5144.      Lisp_Object extent_replica;
  5145. {
  5146.   return make_number (extent_replica_start
  5147.               (decode_extent_replica (extent_replica)));
  5148. }
  5149.  
  5150. DEFUN ("extent-replica-end", Fextent_replica_end, Sextent_replica_end,
  5151.        1, 1, 0,
  5152.  "Return the end of the specified extent replica.\n\
  5153. See `make-extent-replica'.")
  5154.      (extent_replica)
  5155.      Lisp_Object extent_replica;
  5156. {
  5157.   return make_number (extent_replica_end
  5158.               (decode_extent_replica (extent_replica)));
  5159. }
  5160.  
  5161.  
  5162.  
  5163. /* replicating extents */
  5164.  
  5165. struct replicate_extents_arg
  5166. {
  5167.   Bufpos from;
  5168.   Charcount length;
  5169.   struct buffer *buf;
  5170.   Lisp_Object head;
  5171.   Lisp_Object nconc_cell;
  5172. };
  5173.  
  5174. static int
  5175. replicate_extents_mapper (EXTENT extent, void *arg)
  5176. {
  5177.   /* This function can GC */
  5178.   struct replicate_extents_arg *closure = 
  5179.     (struct replicate_extents_arg *) arg;
  5180.   Lisp_Object head = closure->head;
  5181.   Lisp_Object tail = closure->nconc_cell;
  5182.   Charcount start = extent_endpoint_bufpos (extent, 0) - closure->from;
  5183.   Charcount end = extent_endpoint_bufpos (extent, 1) - closure->from;
  5184.   
  5185.   if (inside_undo || extent_duplicable_p (extent))
  5186.     {
  5187.       start = max (start, 0);
  5188.       end = min (end, closure->length);
  5189.  
  5190.       /* Run the copy-function to give an extent the option of
  5191.      not being copied into the string (or kill ring).
  5192.      */
  5193.       if (extent_duplicable_p (extent) &&
  5194.       !run_extent_copy_function_bufpos (extent,
  5195.                         start + closure->from,
  5196.                         end + closure->from))
  5197.     return 0;
  5198.       
  5199.       /* Make a dup and put it on the string-extent-data. */
  5200.       {
  5201.     Lisp_Object new_cell;   
  5202.     Lisp_Object replica;
  5203.     EXTENT_REPLICA dup;
  5204.     
  5205.     XSETEXTENT (replica, extent);
  5206.     dup = make_extent_replica (replica, start, end);
  5207.     XSETEXTENT_REPLICA (replica, dup);
  5208.     new_cell = Fcons (replica, Qnil);
  5209.     
  5210.     if (NILP (head))
  5211.       closure->head = new_cell;
  5212.     else
  5213.       Fsetcdr (tail, new_cell);
  5214.     closure->nconc_cell = new_cell;
  5215.       }
  5216.     }  
  5217.   return 0;
  5218. }
  5219.  
  5220. Lisp_Object 
  5221. replicate_extents (struct buffer *buf, Bufpos opoint, Charcount length)
  5222. {
  5223.   /* This function can GC */
  5224.   struct replicate_extents_arg closure;
  5225.  
  5226.   closure.from = opoint;
  5227.   closure.length = length;
  5228.   closure.head = Qnil;
  5229.   closure.buf = buf;
  5230.   closure.nconc_cell = Qzero;
  5231.   map_extents (opoint, opoint + length, replicate_extents_mapper, 
  5232.            (void *) &closure, make_buffer (buf), 0,
  5233.            /* ignore extents that just abut the region */
  5234.            ME_END_CLOSED | ME_ALL_EXTENTS_OPEN |
  5235.            /* we are calling E-Lisp (the extent's copy function)
  5236.           so anything might happen */
  5237.            ME_MIGHT_CALL_ELISP);
  5238.   return closure.head;
  5239. }
  5240.  
  5241. /* We have just inserted a string of size "length" at "opoint"; the string
  5242.    was taken from an original string at position pos.  We have the contents
  5243.    of the extents slot of the original string on hand, and we now need
  5244.    to do "whatever" is necessary to make the extents in the buffer be
  5245.    correctly updated. If there are no extents on the string, then that is
  5246.    nothing. If there are extents and we are inside_undo, then the extents
  5247.    argument is taken as revealed truth and the state of the buffer extents
  5248.    must be restored so that the function above would return the same string
  5249.    extents if this corresponding string were to be deleted. If we are not
  5250.    inside undo then we just splice in those extents that correspond to
  5251.    deleted extents.
  5252.  
  5253.    Note: At the moment we ONLY handle the case of the dup_list argument
  5254.    be a list of extent_replicas.
  5255.    */
  5256.  
  5257. void 
  5258. splice_in_extent_replicas (struct buffer *buf, Bufpos opoint,
  5259.                Charcount length, Charcount pos,
  5260.                Lisp_Object dup_list)
  5261. {
  5262.   Lisp_Object tail;
  5263.   Bufpos base_start = opoint;
  5264.   Bufpos base_end = opoint + length;
  5265.  
  5266.   if (NILP (dup_list))   
  5267.     return;
  5268.   assert (CONSP (dup_list));
  5269.  
  5270.   for (tail = dup_list; !NILP (tail); tail = Fcdr (tail))
  5271.     {
  5272.       Lisp_Object current_replica = Fcar (tail);
  5273.       /* only process replicas at the moment */
  5274.       if (EXTENT_REPLICAP (current_replica)) 
  5275.     {
  5276.       EXTENT_REPLICA dup = XEXTENT_REPLICA (current_replica);
  5277.       EXTENT extent = XEXTENT (extent_replica_extent (dup));
  5278.       Bufpos new_start = base_start + extent_replica_start (dup) - pos;
  5279.       Bufpos new_end = base_start + extent_replica_end (dup) - pos;
  5280.       Bufpos exstart = 0;
  5281.       Bufpos exend = 0;
  5282.       
  5283.       if (!EXTENT_LIVE_P (extent))
  5284.         continue;
  5285.  
  5286.       if (!extent_detached_p (extent))
  5287.         {
  5288.           exstart = extent_endpoint_bufpos (extent, 0);
  5289.           exend = extent_endpoint_bufpos (extent, 1);
  5290.         }
  5291.  
  5292. #if 0
  5293.       /* utter hogwash.  The "invalid" condition that this code
  5294.          was attempting to catch is in fact quite valid, and occurs
  5295.          often with text properties, because of the way the text-
  5296.          property mechanism re-uses existing extents.  I don't
  5297.          know why this code was in here in the first place, other
  5298.          than a braino on the part of the original implementor. */
  5299.       if (inside_undo)
  5300.         {
  5301.               if (!extent_detached_p (extent) &&
  5302.           (exend > base_end || exstart < base_start))
  5303.                 error ("extent 0x%lx is all fouled up wrt. dup 0x%lx",
  5304.                        (long) extent, (long) dup);
  5305.         }
  5306. #endif
  5307.  
  5308.       /* The extra comparisons defend against set-string-extent-data
  5309.          and support insert_lisp_string.  */
  5310.       if (new_start < base_start)
  5311.         new_start = base_start;
  5312.       if (new_end > base_end)
  5313.         new_end = base_end;
  5314.       if (new_end <= new_start)
  5315.         continue;
  5316.       
  5317. #ifdef ENERGIZE
  5318.       /* Energize extents like toplevel-forms can only be pasted 
  5319.          in the buffer they come from.  This should be parametrized
  5320.          in the generic extent objects.  Right now just silently
  5321.          skip the extents if it's not from the same buffer.
  5322.          */
  5323.       if (XBUFFER (extent_object (extent)) != buf
  5324.           && energize_extent_data (extent))
  5325.         continue;
  5326. #endif
  5327.       
  5328.       /* If this is a `unique' extent, and it is currently attached
  5329.          somewhere other than here (non-overlapping), then don't copy
  5330.          it (that's what `unique' means).  If however it is detached,
  5331.          or if we are inserting inside/adjacent to the original
  5332.          extent, then insert_extent() will simply reattach it, which
  5333.          is what we want.
  5334.          */
  5335.       if (extent_unique_p (extent)
  5336.           && !extent_detached_p (extent)
  5337.           && (XBUFFER (extent_object (extent)) != buf
  5338.           || exend > new_end
  5339.           || exstart < new_start))
  5340.         continue;
  5341.  
  5342.       insert_extent (extent, bufpos_to_bytind (buf, new_start),
  5343.              bufpos_to_bytind (buf, new_end), buf, !inside_undo);
  5344.     }
  5345.     }
  5346. }
  5347.  
  5348. static void 
  5349. add_to_replicas_lists (c_hashtable table,
  5350.                Lisp_Object dup_list,
  5351.                Charcount offset, Charcount length,
  5352.                int clip_parts, Charcount total_length,
  5353.                Lisp_Object *cells_vec)
  5354. {
  5355.   Lisp_Object tail;
  5356.   for (tail = dup_list; !NILP (tail); tail = Fcdr (tail))
  5357.     {
  5358.       Lisp_Object current_replica = Fcar (tail);
  5359.       if (EXTENT_REPLICAP (current_replica)) 
  5360.         {
  5361.           EXTENT_REPLICA dup = XEXTENT_REPLICA (current_replica);
  5362.       Bufpos new_start = extent_replica_start (dup);
  5363.       Bufpos new_end = extent_replica_end (dup);
  5364.           EXTENT extent = XEXTENT (extent_replica_extent (dup));
  5365.           Lisp_Object pre_existing_cell;
  5366.           Lisp_Object tmp;
  5367.           EXTENT_REPLICA new_dup;
  5368.       CONST void *vval;
  5369.  
  5370.       if (clip_parts)
  5371.         {
  5372.           /* The extra clipping defends against set-string-extent-data.
  5373.          It is not necessary in shift_replicas, since the
  5374.          check against total_length still applies below.
  5375.            */
  5376.           if (new_start > length)  new_start = length;
  5377.           if (new_end > length)    new_end = length;
  5378.         }
  5379.  
  5380.       new_start += offset;
  5381.       new_end += offset;
  5382.  
  5383.       /* These checks are needed because of Fsubstring, and are a good
  5384.          idea in any case:
  5385.          */
  5386.       if (new_end <= 0)
  5387.         continue;
  5388.       if (new_start >= total_length)
  5389.         continue;
  5390.       if (new_start <= 0)
  5391.         new_start = 0;
  5392.       if (new_end >= total_length)
  5393.         new_end = total_length;
  5394.  
  5395.           if (!EXTENT_LIVE_P (extent))
  5396.             continue;
  5397.  
  5398.           new_dup = make_extent_replica (extent_replica_extent (dup),
  5399.                      new_start, new_end);
  5400.    
  5401.           if (!gethash ((void *) extent, table, &vval))
  5402.             pre_existing_cell = Qnil;
  5403.       else
  5404.         VOID_TO_LISP (pre_existing_cell, vval);
  5405.    
  5406.           XSETEXTENT_REPLICA (tmp, new_dup);
  5407.           tmp = Fcons (tmp, pre_existing_cell);
  5408.           puthash (extent, LISP_TO_VOID (tmp), table);
  5409.         }
  5410. #if 0
  5411.       else
  5412.     {
  5413.       /* Save away misc. trash in the order encountered. */
  5414.       Lisp_Object cell;
  5415.       cell = Fcons (current_replica, Qnil);
  5416.       if (NILP (cells_vec[0]))
  5417.         cells_vec[0] = cell;
  5418.       else
  5419.         nconc2 (cells_vec[1], cell);
  5420.       cells_vec[1] = cell;
  5421.     }
  5422. #endif
  5423.     }
  5424. }
  5425.  
  5426. /* Merge dup_list[i] into a list of replicas -- if a dup
  5427.    in listi "overlaps at the end" matches a dup from listi+1 that "overlaps
  5428.    at the beginning", merge them into one contiguous dup in the returned
  5429.    list. It is weird and probably bogus if a "detached dup" doesn't merge 
  5430.    entirely, but it isn't an error.
  5431.    
  5432.    This code also handles construction of a dup_list for Fsubstring,
  5433.    by handing in a single list with a possibly negative offset and
  5434.    a length which is possibly less than the length of the original string.
  5435.    */
  5436.    
  5437. static void
  5438. merge_replicas_concating_mapper (CONST void *key, void *contents, void *arg)
  5439. {
  5440.   Lisp_Object extent_cell;
  5441.   Lisp_Object *cells_vec = (Lisp_Object *) arg;
  5442.   VOID_TO_LISP (extent_cell, contents);
  5443.  
  5444.   if (NILP (cells_vec[0]))
  5445.     cells_vec[0] = extent_cell;
  5446.   else
  5447.     nconc2 (cells_vec[1], extent_cell);
  5448.  
  5449.   cells_vec[1] = extent_cell;
  5450.   return;
  5451. }
  5452.  
  5453. static int 
  5454. mrp_pred (Lisp_Object x, Lisp_Object y, Lisp_Object dummy)
  5455. {
  5456.   EXTENT_REPLICA dup1 = XEXTENT_REPLICA (x);
  5457.   EXTENT_REPLICA dup2 = XEXTENT_REPLICA (y);
  5458.  
  5459.   if (extent_replica_start (dup1) < extent_replica_start (dup2))
  5460.     return 1;
  5461.   else if (extent_replica_start (dup1) == extent_replica_start (dup2))
  5462.     {
  5463.       if (extent_replica_end (dup1) <= extent_replica_end (dup2))
  5464.         return 1;
  5465.       else
  5466.         return -1;
  5467.     }
  5468.   return -1;
  5469. }
  5470.    
  5471. static void
  5472. merge_replicas_pruning_mapper (CONST void *key, void *contents, void *arg)
  5473. {
  5474.   Lisp_Object dup_list;
  5475.   c_hashtable table = (c_hashtable) arg;
  5476.   VOID_TO_LISP (dup_list, contents);
  5477.  
  5478.   if (NILP (dup_list))
  5479.     return;
  5480.   if (NILP (Fcdr (dup_list)))
  5481.     return;
  5482.    
  5483.   /* sort and merge the dup_list */
  5484.   dup_list = list_sort (dup_list, Qnil, mrp_pred);
  5485.   {
  5486.     Lisp_Object current = dup_list;
  5487.     Lisp_Object tail = Fcdr (dup_list);
  5488.     EXTENT_REPLICA current_dup = XEXTENT_REPLICA (Fcar (current));
  5489.  
  5490.     while (!NILP (tail))
  5491.       {
  5492.         EXTENT_REPLICA tail_dup = XEXTENT_REPLICA (Fcar (tail));
  5493.  
  5494.         if (extent_replica_start (tail_dup) <=
  5495.         extent_replica_end (current_dup) - 1)
  5496.           {
  5497.             set_extent_replica_end (current_dup,
  5498.                     max (extent_replica_end (tail_dup),
  5499.                      extent_replica_end (current_dup)));
  5500.             Fsetcdr (current, Fcdr (tail));
  5501.           }
  5502.         else
  5503.           {
  5504.             current = tail;
  5505.             current_dup = XEXTENT_REPLICA (Fcar (current));
  5506.           }
  5507.    
  5508.         tail = Fcdr (tail);
  5509.       }
  5510.   }
  5511.    
  5512.   /* now put back the munged list */
  5513.   puthash (key, LISP_TO_VOID (dup_list), table);
  5514. }
  5515.  
  5516. static Lisp_Object 
  5517. merge_replicas_internal (int number_of_lists,
  5518.              struct merge_replicas_struct *vec,
  5519.              int shiftp)
  5520. {
  5521.   c_hashtable table = 0;
  5522.   Lisp_Object cells_vec[2];
  5523.   int i;
  5524.   int total_length;
  5525.   int clip_parts = !shiftp;
  5526.  
  5527.   cells_vec[0] = Qnil;
  5528.   cells_vec[1] = Qnil;
  5529.  
  5530.   total_length = 0;
  5531.   for (i = 0; i < number_of_lists; i++)
  5532.     total_length += vec[i].entry_length;
  5533.  
  5534.   for (i = 0; i < number_of_lists; i++)
  5535.     {
  5536.       Lisp_Object dup_list = vec[i].dup_list;
  5537.       Charcount    offset = vec[i].entry_offset;
  5538.       Charcount length = vec[i].entry_length;
  5539.  
  5540.       if (!NILP (dup_list))
  5541.         {
  5542.           if (!table)
  5543.             table = make_hashtable (10);
  5544.           add_to_replicas_lists (table, dup_list,
  5545.                  offset, length,
  5546.                  clip_parts, total_length,
  5547.                  cells_vec);
  5548.         }
  5549.     }
  5550.  
  5551.   if (table)
  5552.     {
  5553.       maphash (merge_replicas_pruning_mapper,   table, (void*)table);
  5554.       maphash (merge_replicas_concating_mapper, table, (void*)&(cells_vec[0]));
  5555.       free_hashtable (table);
  5556.     }
  5557.   return (cells_vec[0]);
  5558. }
  5559.  
  5560. Lisp_Object 
  5561. merge_replicas (int number_of_lists, struct merge_replicas_struct *vec)
  5562. {
  5563.   return merge_replicas_internal (number_of_lists, vec, 0);
  5564. }
  5565.  
  5566. /* Like merge_replicas, but operates on just one dup_list,
  5567.    applying an offset and clipping the results to [0..length).
  5568.    The offset is non-positive if the caller is Fsubstring.
  5569.    */
  5570. Lisp_Object
  5571. shift_replicas (Lisp_Object dup_list, int offset, int length)
  5572. {
  5573.   struct merge_replicas_struct mr_struct;
  5574.   mr_struct.dup_list = dup_list;
  5575.   mr_struct.entry_offset = offset;
  5576.   mr_struct.entry_length = length;
  5577.   return merge_replicas_internal (1, &mr_struct, 1);
  5578. }
  5579.  
  5580.  
  5581.  
  5582. /* Checklist for sanity checking:
  5583.    - {kill, yank, copy} at {open, closed} {start, end} of {writable, read-only} extent
  5584.    - {kill, copy} & yank {once, repeatedly} duplicable extent in {same, different} buffer
  5585.  */
  5586.  
  5587.  
  5588. /************************************************************************/
  5589. /*                text properties                */
  5590. /************************************************************************/
  5591.  
  5592. /* Text properties
  5593.    Originally this stuff was implemented in lisp (all of the functionality
  5594.    exists to make that possible) but speed was a problem.
  5595.  */
  5596.  
  5597. Lisp_Object Qtext_prop;
  5598. Lisp_Object Qtext_prop_extent_paste_function;
  5599.  
  5600. struct put_text_prop_arg
  5601. {
  5602.   Lisp_Object prop, value;    /* The property and value we are storing */
  5603.   Bytind start, end;    /* The region into which we are storing it */
  5604.   struct buffer *buffer;
  5605.   int changed_p;        /* Output: whether we have modified anything */
  5606.   Lisp_Object the_extent;    /* Our chosen extent; this is used for
  5607.                    communication between subsequent passes. */
  5608. };
  5609.  
  5610. static int
  5611. put_text_prop_mapper (EXTENT e, void *arg)
  5612. {
  5613.   struct put_text_prop_arg *closure = (struct put_text_prop_arg *) arg;
  5614.  
  5615.   Lisp_Object value = closure->value;
  5616.   Bytind e_start, e_end; 
  5617.   Bytind start = closure->start;
  5618.   Bytind end   = closure->end;
  5619.   Lisp_Object extent, e_val;
  5620.   XSETEXTENT (extent, e);
  5621.   e_start = extent_endpoint_bytind (e, 0);
  5622.   e_end   = extent_endpoint_bytind (e, 1);
  5623.   e_val = Fextent_property (extent, closure->prop);
  5624.  
  5625.   if (!EQ (Fextent_property (extent, Qtext_prop), closure->prop))
  5626.     {
  5627.       /* It's not for this property; do nothing. */
  5628.       ;
  5629.     }
  5630.   else if (!NILP (value) &&
  5631.        NILP (closure->the_extent) &&
  5632.        EQ (value, e_val))
  5633.     {
  5634.       /* We want there to be an extent here at the end, and we haven't picked
  5635.      one yet, so use this one.  Extend it as necessary.  We only reuse an
  5636.      extent which has an EQ value for the prop in question to avoid
  5637.      side-effecting the kill ring (that is, we never change the property
  5638.      on an extent after it has been created.)
  5639.        */
  5640.       if (e_start != start || e_end != end)
  5641.     {
  5642.       set_extent_endpoints (e, min (e_start, start),
  5643.                 max (e_end, end));
  5644.       closure->changed_p = 1;
  5645.     }
  5646.       closure->the_extent = extent;
  5647.     }
  5648.  
  5649.   /* Even if we're adding a prop, at this point, we want all other extents of
  5650.      this prop to go away (as now they overlap).  So the theory here is that,
  5651.      when we are adding a prop to a region that has multiple (disjoint)
  5652.      occurences of that prop in it already, we pick one of those and extend
  5653.      it, and remove the others.
  5654.    */
  5655.  
  5656.   else if (EQ (extent, closure->the_extent))
  5657.     {
  5658.       /* just in case map-extents hits it again (does that happen?) */
  5659.       ;
  5660.     }
  5661.   else if (e_start >= start && e_end <= end)
  5662.     {
  5663.       /* Extent is contained in region; remove it.  Don't destroy or modify
  5664.      it, because we don't want to change the attributes pointed to by the
  5665.      duplicates in the kill ring.
  5666.        */
  5667.       extent_detach (e);
  5668.       closure->changed_p = 1;
  5669.     }
  5670.   else if (!NILP (closure->the_extent) &&
  5671.        EQ (value, e_val) &&
  5672.        e_start <= end &&
  5673.        e_end >= start)
  5674.     {
  5675.       EXTENT te = XEXTENT (closure->the_extent);
  5676.       /* This extent overlaps, and has the same prop/value as the extent we've
  5677.      decided to reuse, so we can remove this existing extent as well (the
  5678.      whole thing, even the part outside of the region) and extend
  5679.      the-extent to cover it, resulting in the minimum number of extents in
  5680.      the buffer.
  5681.        */
  5682.       Bytind the_start = extent_endpoint_bytind (te, 0);
  5683.       Bytind the_end = extent_endpoint_bytind (te, 1);
  5684.       if (e_start != the_start &&  /* note AND not OR */
  5685.       e_end   != the_end)
  5686.     {
  5687.       set_extent_endpoints (te,
  5688.                 min (the_start, e_start),
  5689.                 max (the_end,   e_end));
  5690.       closure->changed_p = 1;
  5691.     }
  5692.       extent_detach (e);
  5693.     }
  5694.   else if (e_end <= end)
  5695.     {
  5696.       /* Extent begins before start but ends before end, so we can just
  5697.      decrease its end position.
  5698.        */
  5699.       if (e_end != start)
  5700.     {
  5701.       set_extent_endpoints (e, e_start, start);
  5702.       closure->changed_p = 1;
  5703.     }
  5704.     }
  5705.   else if (e_start >= start)
  5706.     {
  5707.       /* Extent ends after end but begins after start, so we can just
  5708.      increase its start position.
  5709.        */
  5710.       if (e_start != end)
  5711.     {
  5712.       set_extent_endpoints (e, end, e_end);
  5713.       closure->changed_p = 1;
  5714.     }
  5715.     }
  5716.   else
  5717.     {
  5718.       /* Otherwise, `extent' straddles the region.  We need to split it.
  5719.        */
  5720.       set_extent_endpoints (e, e_start, start);
  5721.       copy_extent (e, end, e_end, extent_object (e));
  5722.       closure->changed_p = 1;
  5723.     }
  5724.  
  5725.   return 0;  /* to continue mapping. */
  5726. }
  5727.  
  5728. static int
  5729. put_text_prop (Bytind start, Bytind end, struct buffer *b,
  5730.            Lisp_Object prop, Lisp_Object value,
  5731.            int duplicable_p)
  5732. {
  5733.   /* This function can GC */
  5734.   struct put_text_prop_arg closure;
  5735.   if (start == end)   /* There are no characters in the region. */
  5736.     return 0;
  5737.  
  5738.   closure.prop = prop;
  5739.   closure.value = value;
  5740.   closure.start = start;
  5741.   closure.end = end;
  5742.   closure.buffer = b;
  5743.   closure.changed_p = 0;
  5744.   closure.the_extent = Qnil;
  5745.  
  5746.   map_extents_bytind (start, end,
  5747.               put_text_prop_mapper,
  5748.               (void *) &closure, make_buffer (b), 0,
  5749.               /* get all extents that abut the region */
  5750.               ME_ALL_EXTENTS_CLOSED | ME_END_CLOSED |
  5751.               ME_MIGHT_MODIFY_EXTENTS);
  5752.  
  5753.   /* If we made it through the loop without reusing an extent
  5754.      (and we want there to be one) make it now.
  5755.    */
  5756.   if (!NILP (value) && NILP (closure.the_extent))
  5757.     {
  5758.       Lisp_Object extent = Qnil;
  5759.       Lisp_Object object = Qnil;
  5760.       XSETBUFFER (object, b);
  5761.       XSETEXTENT (extent, make_extent_internal (object, start, end));
  5762.       closure.changed_p = 1;
  5763.       Fset_extent_property (extent, Qtext_prop, prop);
  5764.       Fset_extent_property (extent, prop, value);
  5765.       if (duplicable_p)
  5766.     {
  5767.       extent_duplicable_p (XEXTENT (extent)) = 1;
  5768.       Fset_extent_property (extent, Qpaste_function,
  5769.                 Qtext_prop_extent_paste_function);
  5770.     }
  5771.     }
  5772.  
  5773.   return closure.changed_p;
  5774. }
  5775.  
  5776. DEFUN ("put-text-property", Fput_text_property, Sput_text_property, 4, 5, 0,
  5777.  "Adds the given property/value to all characters in the specified region.\n\
  5778. The property is conceptually attached to the characters rather than the\n\
  5779. region.  The properties are copied when the characters are copied/pasted.")
  5780.      (start, end, prop, value, buffer)
  5781.      Lisp_Object start, end, prop, value, buffer;
  5782. {
  5783.   /* This function can GC */
  5784.   Bytind s, e;
  5785.   struct buffer *b = decode_buffer (buffer, 0);
  5786.   get_bufrange_bytind (b, start, end, &s, &e, 0);
  5787.   CHECK_SYMBOL (prop, 0);
  5788.   put_text_prop (s, e, b, prop, value, 1);
  5789.   return prop;
  5790. }
  5791.  
  5792. DEFUN ("put-nonduplicable-text-property", Fput_nonduplicable_text_property,
  5793.        Sput_nonduplicable_text_property, 4, 5, 0,
  5794.  "Adds the given property/value to all characters in the specified region.\n\
  5795. The property is conceptually attached to the characters rather than the\n\
  5796. region, however the properties will not be copied when the characters\n\
  5797. are copied.")
  5798.      (start, end, prop, value, buffer)
  5799.      Lisp_Object start, end, prop, value, buffer;
  5800. {
  5801.   /* This function can GC */
  5802.   Bytind s, e;
  5803.   struct buffer *b = decode_buffer (buffer, 0);
  5804.   get_bufrange_bytind (b, start, end, &s, &e, 0);
  5805.   CHECK_SYMBOL (prop, 0);
  5806.   put_text_prop (s, e, b, prop, value, 0);
  5807.   return prop;
  5808. }
  5809.  
  5810. DEFUN ("add-text-properties", Fadd_text_properties, Sadd_text_properties,
  5811.        3, 4, 0,
  5812.        "Add properties to the characters from START to END.\n\
  5813. The third argument PROPS is a property list specifying the property values\n\
  5814. to add.  The optional fourth argument, OBJECT, is the buffer containing the\n\
  5815. text.  Returns t if any property was changed, nil otherwise.")
  5816.     (start, end, props, buffer)
  5817.     Lisp_Object start, end, props, buffer;
  5818. {
  5819.   /* This function can GC */
  5820.   int changed = 0;
  5821.   Bytind s, e;
  5822.   struct buffer *b = decode_buffer (buffer, 0);
  5823.   get_bufrange_bytind (b, start, end, &s, &e, 0);
  5824.   CHECK_LIST (props, 0);
  5825.   for (; !NILP (props); props = Fcdr (Fcdr (props)))
  5826.     {
  5827.       Lisp_Object prop = XCAR (props);
  5828.       Lisp_Object value = Fcar (XCDR (props));
  5829.       CHECK_SYMBOL (prop, 0);
  5830.       changed |= put_text_prop (s, e, b, prop, value, 1);
  5831.     }
  5832.   return (changed ? Qt : Qnil);
  5833. }
  5834.  
  5835. DEFUN ("remove-text-properties", Fremove_text_properties,
  5836.        Sremove_text_properties, 3, 4, 0,
  5837.   "Remove the given properties from all characters in the specified region.\n\
  5838. PROPS should be a plist, but the values in that plist are ignored (treated\n\
  5839. as nil).  Returns t if any property was changed, nil otherwise.")
  5840.     (start, end, props, buffer)
  5841.     Lisp_Object start, end, props, buffer;
  5842. {
  5843.   /* This function can GC */
  5844.   int changed = 0;
  5845.   Bytind s, e;
  5846.   struct buffer *b = decode_buffer (buffer, 0);
  5847.   get_bufrange_bytind (b, start, end, &s, &e, 0);
  5848.   CHECK_LIST (props, 0);
  5849.   for (; !NILP (props); props = Fcdr (Fcdr (props)))
  5850.     {
  5851.       Lisp_Object prop = XCAR (props);
  5852.       CHECK_SYMBOL (prop, 0);
  5853.       changed |= put_text_prop (s, e, b, prop, Qnil, 1);
  5854.     }
  5855.   return (changed ? Qt : Qnil);
  5856. }
  5857.  
  5858. /* Whenever a text-prop extent is pasted into a buffer (via `yank' or `insert'
  5859.    or whatever) we attach the properties to the buffer by calling
  5860.    `put-text-property' instead of by simply allowing the extent to be copied or
  5861.    re-attached.  Then we return nil, telling the extents code not to attach it
  5862.    again.  By handing the insertion hackery in this way, we make kill/yank
  5863.    behave consistently with put-text-property and not fragment the extents
  5864.    (since text-prop extents must partition, not overlap).
  5865.  
  5866.    The lisp implementation of this was probably fast enough, but since I moved
  5867.    the rest of the put-text-prop code here, I moved this as well for 
  5868.    completeness. 
  5869.  */
  5870. DEFUN ("text-prop-extent-paste-function", Ftext_prop_extent_paste_function,
  5871.        Stext_prop_extent_paste_function, 3, 3, 0,
  5872.        "Used as the `paste-function' property of `text-prop' extents.")
  5873.      (extent, from, to)
  5874.      Lisp_Object extent, from, to;
  5875. {
  5876.   /* This function can GC */
  5877.   Lisp_Object prop, val;
  5878.   prop = Fextent_property (extent, Qtext_prop);
  5879.   if (NILP (prop))
  5880.     signal_simple_error ("internal error: no text-prop", extent);
  5881.   val = Fextent_property (extent, prop);
  5882.   if (NILP (val))
  5883.     signal_simple_error_2 ("internal error: no text-prop",
  5884.                extent, prop);
  5885.   Fput_text_property (from, to, prop, val, Qnil);
  5886.   return Qnil; /* important! */
  5887. }
  5888.  
  5889. /* This function could easily be written in Lisp but the C code wants
  5890.    to use it in connection with invisible extents (at least currently).
  5891.    If this changes, consider moving this back into Lisp. */
  5892.  
  5893. DEFUN ("next-single-property-change", Fnext_single_property_change,
  5894.        Snext_single_property_change, 2, 4, 0,
  5895.   "Return the position of next property change for a specific property.\n\
  5896. Scans characters forward from POS till it finds a change in the PROP\n\
  5897.  property, then returns the position of the change.  The optional third\n\
  5898.  argument BUFFER is the buffer to scan (defaults to the current buffer).\n\
  5899. The property values are compared with `eq'.\n\
  5900. Return nil if the property is constant all the way to the end of BUFFER.\n\
  5901. If the value is non-nil, it is a position greater than POS, never equal.\n\n\
  5902. If the optional fourth argument LIMIT is non-nil, don't search\n\
  5903.  past position LIMIT; return LIMIT if nothing is found before LIMIT.\n\
  5904. If two or more extents with conflicting non-nil values for PROP overlap\n\
  5905.  a particular character, it is undefined which value is considered to be\n\
  5906.  the value of PROP. (Note that this situation will not happen if you always\n\
  5907.  use the text-property primitives.)")
  5908.   (pos, prop, buffer, limit)
  5909.      Lisp_Object pos, prop, buffer, limit;
  5910. {
  5911.   struct buffer *buf = decode_buffer (buffer, 0);
  5912.   Bufpos bpos = get_bufpos (buf, pos, 0);
  5913.   Bufpos blim;
  5914.   Lisp_Object extent, value;
  5915.   int limit_was_nil;
  5916.  
  5917.   if (NILP (limit))
  5918.     {
  5919.       blim = BUF_ZV (buf);
  5920.       limit_was_nil = 1;
  5921.     }
  5922.   else
  5923.     {
  5924.       blim = get_bufpos (buf, limit, 0);
  5925.       limit_was_nil = 0;
  5926.     }
  5927.   CHECK_SYMBOL (prop, 1);
  5928.  
  5929.   XSETBUFFER (buffer, buf);
  5930.   extent = Fextent_at (make_number (bpos), buffer, prop, Qnil);
  5931.   if (!NILP (extent))
  5932.     value = Fextent_property (extent, prop);
  5933.   else
  5934.     value = Qnil;
  5935.  
  5936.   while (1)
  5937.     {
  5938.       bpos = XINT (Fnext_extent_change (make_number (bpos), buffer));
  5939.       if (bpos >= blim)
  5940.     break; /* property is the same all the way to the end */
  5941.       extent = Fextent_at (make_number (bpos), buffer, prop, Qnil);
  5942.       if ((NILP (extent) && !NILP (value)) ||
  5943.       (!NILP (extent) && !EQ (value, Fextent_property (extent, prop))))
  5944.     return make_number (bpos);
  5945.     }
  5946.  
  5947.   /* I think it's more sensible for this function to return nil always
  5948.      in this situation and it used to do it this way, but it's been changed
  5949.      for FSF compatibility. */
  5950.   if (limit_was_nil)
  5951.     return Qnil;
  5952.   else
  5953.     return make_number (blim);
  5954. }
  5955.  
  5956. /* See comment on previous function about why this is written in C. */
  5957.  
  5958. DEFUN ("previous-single-property-change", Fprevious_single_property_change,
  5959.        Sprevious_single_property_change, 2, 4, 0,
  5960.   "Return the position of next property change for a specific property.\n\
  5961. Scans characters backward from POS till it finds a change in the PROP\n\
  5962.  property, then returns the position of the change.  The optional third\n\
  5963.  argument BUFFER is the buffer to scan (defaults to the current buffer).\n\
  5964. The property values are compared with `eq'.\n\
  5965. Return nil if the property is constant all the way to the start of BUFFER.\n\
  5966. If the value is non-nil, it is a position less than POS, never equal.\n\n\
  5967. If the optional fourth argument LIMIT is non-nil, don't search back\n\
  5968.  past position LIMIT; return LIMIT if nothing is found until LIMIT.\n\
  5969. If two or more extents with conflicting non-nil values for PROP overlap\n\
  5970.  a particular character, it is undefined which value is considered to be\n\
  5971.  the value of PROP. (Note that this situation will not happen if you always\n\
  5972.  use the text-property primitives.)")
  5973.   (pos, prop, buffer, limit)
  5974.      Lisp_Object pos, prop, buffer, limit;
  5975. {
  5976.   struct buffer *buf = decode_buffer (buffer, 0);
  5977.   Bufpos bpos = get_bufpos (buf, pos, 0);
  5978.   Bufpos blim;
  5979.   Lisp_Object extent, value;
  5980.   int limit_was_nil;
  5981.  
  5982.   if (NILP (limit))
  5983.     {
  5984.       blim = BUF_BEGV (buf);
  5985.       limit_was_nil = 1;
  5986.     }
  5987.   else
  5988.     {
  5989.       blim = get_bufpos (buf, limit, 0);
  5990.       limit_was_nil = 0;
  5991.     }
  5992.   CHECK_SYMBOL (prop, 1);
  5993.  
  5994.   XSETBUFFER (buffer, buf);
  5995.   /* extent-at refers to the character AFTER bpos, but we want the
  5996.      character before bpos.  Thus the - 1.  extent-at simply
  5997.      returns nil on bogus positions, so not to worry. */
  5998.   extent = Fextent_at (make_number (bpos - 1), buffer, prop, Qnil);
  5999.   if (!NILP (extent))
  6000.     value = Fextent_property (extent, prop);
  6001.   else
  6002.     value = Qnil;
  6003.  
  6004.   while (1)
  6005.     {
  6006.       bpos = XINT (Fprevious_extent_change (make_number (bpos), buffer));
  6007.       if (bpos <= blim)
  6008.     break; /* property is the same all the way to the beginning */
  6009.       extent = Fextent_at (make_number (bpos - 1), buffer, prop, Qnil);
  6010.       if ((NILP (extent) && !NILP (value)) ||
  6011.       (!NILP (extent) && !EQ (value, Fextent_property (extent, prop))))
  6012.     return make_number (bpos);
  6013.     }
  6014.   
  6015.   /* I think it's more sensible for this function to return nil always
  6016.      in this situation and it used to do it this way, but it's been changed
  6017.      for FSF compatibility. */
  6018.   if (limit_was_nil)
  6019.     return Qnil;
  6020.   else
  6021.     return make_number (blim);
  6022. }
  6023.  
  6024.  
  6025. /************************************************************************/
  6026. /*                initialization                */
  6027. /************************************************************************/
  6028.  
  6029. void
  6030. syms_of_extents (void)
  6031. {
  6032.   defsymbol (&Qextentp, "extentp");
  6033.   defsymbol (&Qextent_replicap, "extent-replicap");
  6034.   defsymbol (&Qextent_live_p, "extent-live-p");
  6035.   defsymbol (&Qextent_replica_live_p, "extent-replica-live-p");
  6036.  
  6037.   defsymbol (&Qend_closed, "end-closed");
  6038.   defsymbol (&Qstart_open, "start-open");
  6039.   defsymbol (&Qall_extents_closed, "all-extents-closed");
  6040.   defsymbol (&Qall_extents_open, "all-extents-open");
  6041.   defsymbol (&Qall_extents_closed_open, "all-extents-closed-open");
  6042.   defsymbol (&Qall_extents_open_closed, "all-extents-open-closed");
  6043.   defsymbol (&Qstart_in_region, "start-in-region");
  6044.   defsymbol (&Qend_in_region, "end-in-region");
  6045.   defsymbol (&Qstart_and_end_in_region, "start-and-end-in-region");
  6046.   defsymbol (&Qstart_or_end_in_region, "start-or-end-in-region");
  6047.   defsymbol (&Qnegate_in_region, "negate-in-region");
  6048.  
  6049.   defsymbol (&Qdetached, "detached");
  6050.   defsymbol (&Qdestroyed, "destroyed");
  6051.   defsymbol (&Qbegin_glyph, "begin-glyph");
  6052.   defsymbol (&Qend_glyph, "end-glyph");
  6053.   defsymbol (&Qstart_open, "start-open");
  6054.   defsymbol (&Qend_open, "end-open");
  6055.   defsymbol (&Qstart_closed, "start-closed");
  6056.   defsymbol (&Qend_closed, "end-closed");
  6057.   defsymbol (&Qread_only, "read-only");
  6058.   /* defsymbol (&Qhighlight, "highlight"); in faces.c */
  6059.   defsymbol (&Qunique, "unique");
  6060.   defsymbol (&Qduplicable, "duplicable");
  6061.   defsymbol (&Qinvisible, "invisible");
  6062.   defsymbol (&Qintangible, "intangible");
  6063.   defsymbol (&Qdetachable, "detachable");
  6064.   defsymbol (&Qpriority, "priority");
  6065.  
  6066.   defsymbol (&Qglyph_layout, "glyph-layout");    /* backwards compatibility */
  6067.   defsymbol (&Qbegin_glyph_layout, "begin-glyph-layout");
  6068.   defsymbol (&Qbegin_glyph_layout, "end-glyph-layout");
  6069.   defsymbol (&Qoutside_margin, "outside-margin");
  6070.   defsymbol (&Qinside_margin, "inside-margin");
  6071.   defsymbol (&Qwhitespace, "whitespace");
  6072.   /* Qtext defined in general.c */
  6073.  
  6074.   defsymbol (&Qglyph_invisible, "glyph-invisible");
  6075.  
  6076.   defsymbol (&Qpaste_function, "paste-function");
  6077.   defsymbol (&Qcopy_function,  "copy-function");
  6078.  
  6079.   defsymbol (&Qtext_prop, "text-prop");
  6080.   defsymbol (&Qtext_prop_extent_paste_function,
  6081.          "text-prop-extent-paste-function");
  6082.  
  6083.   defsymbol (&Qdup_list, "dup-list");
  6084.  
  6085.   defsubr (&Sextentp);
  6086.   defsubr (&Sextent_live_p);
  6087.   defsubr (&Sextent_detached_p);
  6088.   defsubr (&Sextent_start_position);
  6089.   defsubr (&Sextent_end_position);
  6090.   defsubr (&Sextent_object);
  6091.   defsubr (&Sextent_length);
  6092. #if 0
  6093.   defsubr (&Sstack_of_extents);
  6094. #endif
  6095.  
  6096.   defsubr (&Smake_extent);
  6097.   defsubr (&Scopy_extent);
  6098.   defsubr (&Sdelete_extent);
  6099.   defsubr (&Sdetach_extent);
  6100.   defsubr (&Sset_extent_endpoints);
  6101.   defsubr (&Snext_extent);
  6102.   defsubr (&Sprevious_extent);
  6103. #if DEBUG_XEMACS
  6104.   defsubr (&Snext_e_extent);
  6105.   defsubr (&Sprevious_e_extent);
  6106. #endif
  6107.   defsubr (&Snext_extent_change);
  6108.   defsubr (&Sprevious_extent_change);
  6109.  
  6110.   defsubr (&Sextent_parent);
  6111.   defsubr (&Sextent_children);
  6112.   defsubr (&Sset_extent_parent);
  6113.  
  6114.   defsubr (&Sextent_in_region_p);
  6115.   defsubr (&Smap_extents);
  6116.   defsubr (&Smap_extent_children);
  6117.   defsubr (&Sextent_at);
  6118.  
  6119.   defsubr (&Sset_extent_begin_glyph);
  6120.   defsubr (&Sset_extent_end_glyph);
  6121.   defsubr (&Sextent_begin_glyph);
  6122.   defsubr (&Sextent_end_glyph);
  6123.   defsubr (&Sset_extent_begin_glyph_layout);
  6124.   defsubr (&Sset_extent_end_glyph_layout);
  6125.   defsubr (&Sextent_begin_glyph_layout);
  6126.   defsubr (&Sextent_end_glyph_layout);
  6127.   defsubr (&Sset_extent_priority);
  6128.   defsubr (&Sextent_priority);
  6129.   defsubr (&Sset_extent_property);
  6130.   defsubr (&Sextent_property);
  6131.   defsubr (&Sextent_properties);
  6132.  
  6133.   defsubr (&Shighlight_extent);
  6134.   defsubr (&Sforce_highlight_extent);
  6135.  
  6136.   defsubr (&Sinsert_extent);
  6137.   defsubr (&Sstring_extent_data);
  6138.   defsubr (&Sset_string_extent_data);
  6139.   defsubr (&Smake_extent_replica);
  6140.   defsubr (&Sextent_replica_p);
  6141.   defsubr (&Sextent_replica_live_p);
  6142.   defsubr (&Sextent_replica_extent);
  6143.   defsubr (&Sextent_replica_start);
  6144.   defsubr (&Sextent_replica_end);
  6145.  
  6146.   defsubr (&Sput_text_property);
  6147.   defsubr (&Sput_nonduplicable_text_property);
  6148.   defsubr (&Sadd_text_properties);
  6149.   defsubr (&Sremove_text_properties);
  6150.   defsubr (&Stext_prop_extent_paste_function);
  6151.   defsubr (&Snext_single_property_change);
  6152.   defsubr (&Sprevious_single_property_change);
  6153. }
  6154.  
  6155. void
  6156. vars_of_extents (void)
  6157. {
  6158.   DEFVAR_INT ("mouse-highlight-priority", &mouse_highlight_priority,
  6159. "The priority to use for the mouse-highlighting pseudo-extent\n\
  6160. that is used to highlight extents with the `highlight' attribute set.\n\
  6161. See `set-extent-priority'.");
  6162.   /* Set mouse-highlight-priority (which ends up being used both for the
  6163.      mouse-highlighting pseudo-extent and the primary selection extent)
  6164.      to a very high value because very few extents should override it.
  6165.      1000 gives lots of room below it for different-prioritied extents.
  6166.      10 doesn't. ediff, for example, likes to use priorities around 100.
  6167.      --ben */
  6168.   mouse_highlight_priority = /* 10 */ 1000;
  6169.  
  6170.   staticpro (&Vlast_highlighted_extent);
  6171.   Vlast_highlighted_extent = Qnil;
  6172.  
  6173.   extent_auxiliary_defaults.begin_glyph = Qnil;
  6174.   extent_auxiliary_defaults.end_glyph = Qnil;
  6175.   extent_auxiliary_defaults.parent = Qnil;
  6176.   extent_auxiliary_defaults.children = Qnil;
  6177.   extent_auxiliary_defaults.priority = 0;
  6178.  
  6179.   staticpro (&Vthis_is_a_dead_extent_replica);
  6180.   XSETEXTENT (Vthis_is_a_dead_extent_replica, make_extent ());
  6181. }
  6182.